1
0
Fork 0
mirror of https://github.com/gwm17/implot.git synced 2024-11-13 22:48:50 -05:00
implot/implot.cpp

2664 lines
120 KiB
C++
Raw Normal View History

2020-04-27 11:27:59 -04:00
// MIT License
// Copyright (c) 2020 Evan Pezent
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
2020-08-07 14:04:31 -04:00
// ImPlot v0.5 WIP
2020-05-11 07:12:22 -04:00
/*
API BREAKING CHANGES
====================
Occasionally introducing changes that are breaking the API. We try to make the breakage minor and easy to fix.
Below is a change-log of API breaking changes only. If you are using one of the functions listed, expect to have to fix some code.
When you are not sure about a old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all implot files.
You can read releases logs https://github.com/epezent/implot/releases for more details.
- 2020/08/17 (0.5) - PlotText was changed so that text is centered horizontally and vertically about the desired point.
- 2020/08/16 (0.5) - An ImPlotContext must be explicitly created and destroyed now with `CreateContext` and `DestroyContext`. Previously, the context was statically initialized in this source file.
- 2020/06/13 (0.4) - The flags `ImPlotAxisFlag_Adaptive` and `ImPlotFlags_Cull` were removed. Both are now done internally by default.
- 2020/06/03 (0.3) - The signature and behavior of PlotPieChart was changed so that data with sum less than 1 can optionally be normalized. The label format can now be specified as well.
2020-06-02 13:34:14 -04:00
- 2020/06/01 (0.3) - SetPalette was changed to `SetColormap` for consistency with other plotting libraries. `RestorePalette` was removed. Use `SetColormap(ImPlotColormap_Default)`.
- 2020/05/31 (0.3) - Plot functions taking custom ImVec2* getters were removed. Use the ImPlotPoint* getter versions instead.
2020-05-29 13:39:30 -04:00
- 2020/05/29 (0.3) - The signature of ImPlotLimits::Contains was changed to take two doubles instead of ImVec2
- 2020/05/16 (0.2) - All plotting functions were reverted to being prefixed with "Plot" to maintain a consistent VerbNoun style. `Plot` was split into `PlotLine`
2020-05-16 10:14:48 -04:00
and `PlotScatter` (however, `PlotLine` can still be used to plot scatter points as `Plot` did before.). `Bar` is not `PlotBars`, to indicate
that multiple bars will be plotted.
- 2020/05/13 (0.2) - `ImMarker` was change to `ImPlotMarker` and `ImAxisFlags` was changed to `ImPlotAxisFlags`.
- 2020/05/11 (0.2) - `ImPlotFlags_Selection` was changed to `ImPlotFlags_BoxSelect`
2020-05-12 05:19:04 -04:00
- 2020/05/11 (0.2) - The namespace ImGui:: was replaced with ImPlot::. As a result, the following additional changes were made:
2020-05-16 10:14:48 -04:00
- Functions that were prefixed or decorated with the word "Plot" have been truncated. E.g., `ImGui::PlotBars` is now just `ImPlot::Bar`.
2020-05-12 05:19:04 -04:00
It should be fairly obvious what was what.
2020-05-13 10:11:25 -04:00
- Some functions have been given names that would have otherwise collided with the ImGui namespace. This has been done to maintain a consistent
style with ImGui. E.g., 'ImGui::PushPlotStyleVar` is now 'ImPlot::PushStyleVar'.
2020-05-11 07:12:22 -04:00
- 2020/05/10 (0.2) - The following function/struct names were changes:
- ImPlotRange -> ImPlotLimits
- GetPlotRange() -> GetPlotLimits()
2020-05-13 10:11:25 -04:00
- SetNextPlotRange -> SetNextPlotLimits
2020-05-11 07:12:22 -04:00
- SetNextPlotRangeX -> SetNextPlotLimitsX
- SetNextPlotRangeY -> SetNextPlotLimitsY
- 2020/05/10 (0.2) - Plot queries are pixel based by default. Query rects that maintain relative plot position have been removed. This was done to support multi-y-axis.
*/
#include "implot.h"
2020-08-16 16:38:51 -04:00
#include "implot_internal.h"
#ifdef _MSC_VER
#define sprintf sprintf_s
#endif
2020-04-27 11:27:59 -04:00
2020-08-16 16:38:51 -04:00
// Global plot context
ImPlotContext* GImPlot = NULL;
2020-08-16 16:38:51 -04:00
//-----------------------------------------------------------------------------
// Struct Implementations
//-----------------------------------------------------------------------------
2020-04-27 11:27:59 -04:00
2020-08-16 16:38:51 -04:00
ImPlotRange::ImPlotRange() {
Min = NAN;
Max = NAN;
}
2020-05-29 13:39:30 -04:00
2020-08-24 00:45:42 -04:00
ImPlotInputMap::ImPlotInputMap() {
PanButton = ImGuiMouseButton_Left;
PanMod = ImGuiKeyModFlags_None;
FitButton = ImGuiMouseButton_Left;
ContextMenuButton = ImGuiMouseButton_Right;
BoxSelectButton = ImGuiMouseButton_Right;
BoxSelectMod = ImGuiKeyModFlags_None;
BoxSelectCancelButton = ImGuiMouseButton_Left;
QueryButton = ImGuiMouseButton_Middle;
QueryMod = ImGuiKeyModFlags_None;
QueryToggleMod = ImGuiKeyModFlags_Ctrl;
HorizontalMod = ImGuiKeyModFlags_Alt;
VerticalMod = ImGuiKeyModFlags_Shift;
}
2020-04-27 11:27:59 -04:00
ImPlotStyle::ImPlotStyle() {
2020-08-16 16:38:51 -04:00
LineWeight = 1;
Marker = ImPlotMarker_None;
MarkerSize = 4;
MarkerWeight = 1;
FillAlpha = 1;
ErrorBarSize = 5;
ErrorBarWeight = 1.5f;
DigitalBitHeight = 8;
2020-08-16 16:38:51 -04:00
DigitalBitGap = 4;
2020-08-24 00:45:42 -04:00
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);
2020-08-24 00:45:42 -04:00
LabelPadding = ImVec2(5,5);
LegendPadding = ImVec2(10,10);
InfoPadding = ImVec2(10,10);
PlotMinSize = ImVec2(300,225);
2020-04-27 11:27:59 -04:00
2020-08-24 12:06:29 -04:00
ImPlot::StyleColorsAuto(this);
}
2020-08-24 00:45:42 -04:00
namespace ImPlot {
const char* GetStyleColorName(ImPlotCol col) {
static const char* col_names[] = {
"Line",
"Fill",
"MarkerOutline",
"MarkerFill",
"ErrorBar",
"FrameBg",
"PlotBg",
"PlotBorder",
"LegendBg",
"LegendBorder",
"LegendText",
"TitleText",
"InlayText",
"XAxis",
"XAxisGrid",
"YAxis",
"YAxisGrid",
"YAxis2",
"YAxisGrid2",
"YAxis3",
"YAxisGrid3",
"Selection",
"Query",
"Crosshairs"
};
return col_names[col];
}
ImVec4 GetAutoColor(ImPlotCol idx) {
ImVec4 col(0,0,0,1);
switch(idx) {
case ImPlotCol_Line: return col; // these are plot dependent!
case ImPlotCol_Fill: return col; // these are plot dependent!
case ImPlotCol_MarkerOutline: return col; // these are plot dependent!
case ImPlotCol_MarkerFill: return col; // these are plot dependent!
case ImPlotCol_ErrorBar: return ImGui::GetStyleColorVec4(ImGuiCol_Text);
case ImPlotCol_FrameBg: return ImGui::GetStyleColorVec4(ImGuiCol_FrameBg);
case ImPlotCol_PlotBg: return ImGui::GetStyleColorVec4(ImGuiCol_WindowBg);
2020-08-24 12:06:29 -04:00
case ImPlotCol_PlotBorder: return ImGui::GetStyleColorVec4(ImGuiCol_Border);
2020-08-24 00:45:42 -04:00
case ImPlotCol_LegendBg: return ImGui::GetStyleColorVec4(ImGuiCol_PopupBg);
case ImPlotCol_LegendBorder: return GetStyleColorVec4(ImPlotCol_PlotBorder);
case ImPlotCol_LegendText: return GetStyleColorVec4(ImPlotCol_InlayText);
case ImPlotCol_TitleText: return ImGui::GetStyleColorVec4(ImGuiCol_Text);
case ImPlotCol_InlayText: return ImGui::GetStyleColorVec4(ImGuiCol_Text);
case ImPlotCol_XAxis: return ImGui::GetStyleColorVec4(ImGuiCol_Text);
case ImPlotCol_XAxisGrid: return GetStyleColorVec4(ImPlotCol_XAxis) * ImVec4(1,1,1,0.25f);
case ImPlotCol_YAxis: return ImGui::GetStyleColorVec4(ImGuiCol_Text);
case ImPlotCol_YAxisGrid: return GetStyleColorVec4(ImPlotCol_YAxis) * ImVec4(1,1,1,0.25f);
case ImPlotCol_YAxis2: return ImGui::GetStyleColorVec4(ImGuiCol_Text);
case ImPlotCol_YAxisGrid2: return GetStyleColorVec4(ImPlotCol_YAxis2) * ImVec4(1,1,1,0.25f);
case ImPlotCol_YAxis3: return ImGui::GetStyleColorVec4(ImGuiCol_Text);
case ImPlotCol_YAxisGrid3: return GetStyleColorVec4(ImPlotCol_YAxis3) * ImVec4(1,1,1,0.25f);
case ImPlotCol_Selection: return ImVec4(1,1,0,1);
case ImPlotCol_Query: return ImVec4(0,1,0,1);
case ImPlotCol_Crosshairs: return GetStyleColorVec4(ImPlotCol_PlotBorder);
default: return col;
}
}
2020-08-24 00:45:42 -04:00
struct ImPlotStyleVarInfo {
ImGuiDataType Type;
ImU32 Count;
ImU32 Offset;
void* GetVarPtr(ImPlotStyle* style) const { return (void*)((unsigned char*)style + Offset); }
};
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, 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
};
static const ImPlotStyleVarInfo* GetPlotStyleVarInfo(ImPlotStyleVar idx) {
IM_ASSERT(idx >= 0 && idx < ImPlotStyleVar_COUNT);
IM_ASSERT(IM_ARRAYSIZE(GPlotStyleVarInfo) == ImPlotStyleVar_COUNT);
return &GPlotStyleVarInfo[idx];
}
2020-04-27 11:27:59 -04:00
2020-05-03 01:24:10 -04:00
//-----------------------------------------------------------------------------
2020-08-16 16:38:51 -04:00
// Generic Helpers
2020-05-03 01:24:10 -04:00
//-----------------------------------------------------------------------------
2020-04-27 11:27:59 -04:00
2020-08-24 09:51:03 -04:00
void AddTextVertical(ImDrawList *DrawList, ImVec2 pos, ImU32 col, const char *text_begin, const char* text_end) {
if (!text_end)
text_end = text_begin + strlen(text_begin);
ImGuiContext& g = *GImGui;
ImFont* font = g.Font;
pos.x = IM_FLOOR(pos.x + font->DisplayOffset.y);
pos.y = IM_FLOOR(pos.y + font->DisplayOffset.x);
const char* s = text_begin;
const int vtx_count = (int)(text_end - s) * 4;
const int idx_count = (int)(text_end - s) * 6;
DrawList->PrimReserve(idx_count, vtx_count);
const float scale = g.FontSize / font->FontSize;
while (s < text_end) {
unsigned int c = (unsigned int)*s;
if (c < 0x80) {
s += 1;
}
else {
s += ImTextCharFromUtf8(&c, s, text_end);
if (c == 0) // Malformed UTF-8?
break;
}
const ImFontGlyph * glyph = font->FindGlyph((ImWchar)c);
if (glyph == NULL)
2020-04-27 11:27:59 -04:00
continue;
2020-08-24 09:51:03 -04:00
DrawList->PrimQuadUV(pos + ImVec2(glyph->Y0, -glyph->X0) * scale, pos + ImVec2(glyph->Y0, -glyph->X1) * scale,
pos + ImVec2(glyph->Y1, -glyph->X1) * scale, pos + ImVec2(glyph->Y1, -glyph->X0) * scale,
ImVec2(glyph->U0, glyph->V0), ImVec2(glyph->U1, glyph->V0),
ImVec2(glyph->U1, glyph->V1), ImVec2(glyph->U0, glyph->V1),
col);
pos.y -= glyph->AdvanceX * scale;
2020-04-27 11:27:59 -04:00
}
}
2020-08-16 16:38:51 -04:00
ImVec2 CalcTextSizeVertical(const char *text) {
2020-05-12 05:19:04 -04:00
ImVec2 sz = ImGui::CalcTextSize(text);
2020-04-27 11:27:59 -04:00
return ImVec2(sz.y, sz.x);
}
2020-08-16 16:38:51 -04:00
double NiceNum(double x, bool round) {
double f; /* fractional part of x */
double nf; /* nice, rounded fraction */
int expv = (int)floor(ImLog10(x));
f = x / ImPow(10.0, (double)expv); /* between 1 and 10 */
if (round)
if (f < 1.5)
nf = 1;
else if (f < 3)
nf = 2;
else if (f < 7)
nf = 5;
else
nf = 10;
else if (f <= 1)
nf = 1;
else if (f <= 2)
nf = 2;
else if (f <= 5)
nf = 5;
else
nf = 10;
return nf * ImPow(10.0, expv);
2020-06-13 13:42:47 -04:00
}
2020-05-03 01:24:10 -04:00
//-----------------------------------------------------------------------------
2020-08-16 16:38:51 -04:00
// Context Utils
2020-05-03 01:24:10 -04:00
//-----------------------------------------------------------------------------
ImPlotContext* CreateContext() {
ImPlotContext* ctx = IM_NEW(ImPlotContext)();
2020-08-16 16:38:51 -04:00
Initialize(ctx);
if (GImPlot == NULL)
SetCurrentContext(ctx);
return ctx;
}
void DestroyContext(ImPlotContext* ctx) {
if (ctx == NULL)
ctx = GImPlot;
if (GImPlot == ctx)
SetCurrentContext(NULL);
IM_DELETE(ctx);
2020-08-16 16:38:51 -04:00
}
ImPlotContext* GetCurrentContext() {
return GImPlot;
}
void SetCurrentContext(ImPlotContext* ctx) {
GImPlot = ctx;
}
2020-04-27 11:27:59 -04:00
2020-08-16 16:38:51 -04:00
void Initialize(ImPlotContext* ctx) {
Reset(ctx);
ctx->Colormap = GetColormap(ImPlotColormap_Default, &ctx->ColormapSize);
2020-08-16 16:38:51 -04:00
}
void Reset(ImPlotContext* ctx) {
// end child window if it was made
if (ctx->ChildWindowMade)
ImGui::EndChild();
ctx->ChildWindowMade = false;
// reset the next plot data
ctx->NextPlotData = ImPlotNextPlotData();
// reset items count
ctx->VisibleItemCount = 0;
// reset legend items
ctx->LegendIndices.shrink(0);
ctx->LegendLabels.Buf.shrink(0);
// reset ticks/labels
2020-08-25 22:59:43 -04:00
ctx->XTicks.Reset();
2020-08-16 16:38:51 -04:00
for (int i = 0; i < 3; ++i) {
2020-08-25 22:59:43 -04:00
ctx->YTicks[i].Reset();
2020-08-16 16:38:51 -04:00
}
2020-08-20 00:50:12 -04:00
// reset extents/fit
ctx->FitThisFrame = false;
2020-08-16 16:38:51 -04:00
ctx->FitX = false;
ctx->ExtentsX.Min = HUGE_VAL;
ctx->ExtentsX.Max = -HUGE_VAL;
for (int i = 0; i < IMPLOT_Y_AXES; i++) {
2020-08-16 16:38:51 -04:00
ctx->ExtentsY[i].Min = HUGE_VAL;
ctx->ExtentsY[i].Max = -HUGE_VAL;
ctx->FitY[i] = false;
}
// reset digital plot items count
ctx->DigitalPlotItemCnt = 0;
ctx->DigitalPlotOffset = 0;
// nullify plot
ctx->CurrentPlot = NULL;
}
2020-05-03 01:24:10 -04:00
//-----------------------------------------------------------------------------
2020-08-16 16:38:51 -04:00
// Plot Utils
2020-05-03 01:24:10 -04:00
//-----------------------------------------------------------------------------
2020-08-16 16:38:51 -04:00
ImPlotState* GetPlot(const char* title) {
ImGuiWindow* Window = GImGui->CurrentWindow;
const ImGuiID ID = Window->GetID(title);
return GImPlot->Plots.GetByKey(ID);
}
ImPlotState* GetCurrentPlot() {
return GImPlot->CurrentPlot;
}
2020-08-24 00:45:42 -04:00
void BustPlotCache() {
GImPlot->Plots.Clear();
}
2020-08-16 16:38:51 -04:00
void FitPoint(const ImPlotPoint& p) {
ImPlotContext& gp = *GImPlot;
const int y_axis = gp.CurrentPlot->CurrentYAxis;
ImPlotRange& ex_x = gp.ExtentsX;
ImPlotRange& ex_y = gp.ExtentsY[y_axis];
const bool log_x = ImHasFlag(gp.CurrentPlot->XAxis.Flags, ImPlotAxisFlags_LogScale);
const bool log_y = ImHasFlag(gp.CurrentPlot->YAxis[y_axis].Flags, ImPlotAxisFlags_LogScale);
if (!NanOrInf(p.x) && !(log_x && p.x <= 0)) {
ex_x.Min = p.x < ex_x.Min ? p.x : ex_x.Min;
ex_x.Max = p.x > ex_x.Max ? p.x : ex_x.Max;
2020-05-03 01:24:10 -04:00
}
if (!NanOrInf(p.y) && !(log_y && p.y <= 0)) {
ex_y.Min = p.y < ex_y.Min ? p.y : ex_y.Min;
ex_y.Max = p.y > ex_y.Max ? p.y : ex_y.Max;
2020-05-03 01:24:10 -04:00
}
}
//-----------------------------------------------------------------------------
2020-08-16 16:38:51 -04:00
// Coordinate Utils
2020-05-03 01:24:10 -04:00
//-----------------------------------------------------------------------------
2020-08-16 16:38:51 -04:00
void UpdateTransformCache() {
ImPlotContext& gp = *GImPlot;
2020-05-03 01:24:10 -04:00
// get pixels for transforms
for (int i = 0; i < IMPLOT_Y_AXES; i++) {
2020-08-16 16:38:51 -04:00
gp.PixelRange[i] = ImRect(ImHasFlag(gp.CurrentPlot->XAxis.Flags, ImPlotAxisFlags_Invert) ? gp.BB_Plot.Max.x : gp.BB_Plot.Min.x,
ImHasFlag(gp.CurrentPlot->YAxis[i].Flags, ImPlotAxisFlags_Invert) ? gp.BB_Plot.Min.y : gp.BB_Plot.Max.y,
ImHasFlag(gp.CurrentPlot->XAxis.Flags, ImPlotAxisFlags_Invert) ? gp.BB_Plot.Min.x : gp.BB_Plot.Max.x,
ImHasFlag(gp.CurrentPlot->YAxis[i].Flags, ImPlotAxisFlags_Invert) ? gp.BB_Plot.Max.y : gp.BB_Plot.Min.y);
2020-05-11 07:12:22 -04:00
gp.My[i] = (gp.PixelRange[i].Max.y - gp.PixelRange[i].Min.y) / gp.CurrentPlot->YAxis[i].Range.Size();
}
2020-05-29 13:39:30 -04:00
gp.LogDenX = ImLog10(gp.CurrentPlot->XAxis.Range.Max / gp.CurrentPlot->XAxis.Range.Min);
for (int i = 0; i < IMPLOT_Y_AXES; i++) {
2020-05-29 13:39:30 -04:00
gp.LogDenY[i] = ImLog10(gp.CurrentPlot->YAxis[i].Range.Max / gp.CurrentPlot->YAxis[i].Range.Min);
2020-05-11 07:12:22 -04:00
}
gp.Mx = (gp.PixelRange[0].Max.x - gp.PixelRange[0].Min.x) / gp.CurrentPlot->XAxis.Range.Size();
2020-04-28 01:38:52 -04:00
}
2020-04-27 11:27:59 -04:00
2020-08-16 16:38:51 -04:00
ImPlotPoint PixelsToPlot(float x, float y, int y_axis_in) {
ImPlotContext& gp = *GImPlot;
2020-06-03 15:37:01 -04:00
IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "PixelsToPlot() needs to be called between BeginPlot() and EndPlot()!");
2020-05-11 07:12:22 -04:00
const int y_axis = y_axis_in >= 0 ? y_axis_in : gp.CurrentPlot->CurrentYAxis;
2020-05-16 22:09:36 -04:00
ImPlotPoint plt;
2020-05-11 07:12:22 -04:00
plt.x = (x - gp.PixelRange[y_axis].Min.x) / gp.Mx + gp.CurrentPlot->XAxis.Range.Min;
plt.y = (y - gp.PixelRange[y_axis].Min.y) / gp.My[y_axis] + gp.CurrentPlot->YAxis[y_axis].Range.Min;
2020-08-16 16:38:51 -04:00
if (ImHasFlag(gp.CurrentPlot->XAxis.Flags, ImPlotAxisFlags_LogScale)) {
2020-05-29 13:39:30 -04:00
double t = (plt.x - gp.CurrentPlot->XAxis.Range.Min) / gp.CurrentPlot->XAxis.Range.Size();
plt.x = ImPow(10, t * gp.LogDenX) * gp.CurrentPlot->XAxis.Range.Min;
2020-05-03 01:24:10 -04:00
}
2020-08-16 16:38:51 -04:00
if (ImHasFlag(gp.CurrentPlot->YAxis[y_axis].Flags, ImPlotAxisFlags_LogScale)) {
2020-05-29 13:39:30 -04:00
double t = (plt.y - gp.CurrentPlot->YAxis[y_axis].Range.Min) / gp.CurrentPlot->YAxis[y_axis].Range.Size();
plt.y = ImPow(10, t * gp.LogDenY[y_axis]) * gp.CurrentPlot->YAxis[y_axis].Range.Min;
2020-05-03 01:24:10 -04:00
}
return plt;
}
2020-05-16 22:09:36 -04:00
ImPlotPoint PixelsToPlot(const ImVec2& pix, int y_axis) {
2020-05-15 09:05:02 -04:00
return PixelsToPlot(pix.x, pix.y, y_axis);
}
// This function is convenient but should not be used to process a high volume of points. Use the Transformer structs below instead.
2020-08-16 16:38:51 -04:00
ImVec2 PlotToPixels(double x, double y, int y_axis_in) {
ImPlotContext& gp = *GImPlot;
2020-06-03 15:37:01 -04:00
IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "PlotToPixels() needs to be called between BeginPlot() and EndPlot()!");
2020-05-11 07:12:22 -04:00
const int y_axis = y_axis_in >= 0 ? y_axis_in : gp.CurrentPlot->CurrentYAxis;
2020-05-03 01:24:10 -04:00
ImVec2 pix;
2020-08-16 16:38:51 -04:00
if (ImHasFlag(gp.CurrentPlot->XAxis.Flags, ImPlotAxisFlags_LogScale)) {
2020-05-29 13:39:30 -04:00
double t = ImLog10(x / gp.CurrentPlot->XAxis.Range.Min) / gp.LogDenX;
2020-05-16 22:09:36 -04:00
x = ImLerp(gp.CurrentPlot->XAxis.Range.Min, gp.CurrentPlot->XAxis.Range.Max, (float)t);
2020-05-13 10:11:25 -04:00
}
2020-08-16 16:38:51 -04:00
if (ImHasFlag(gp.CurrentPlot->YAxis[y_axis].Flags, ImPlotAxisFlags_LogScale)) {
2020-05-29 13:39:30 -04:00
double t = ImLog10(y / gp.CurrentPlot->YAxis[y_axis].Range.Min) / gp.LogDenY[y_axis];
2020-05-16 22:09:36 -04:00
y = ImLerp(gp.CurrentPlot->YAxis[y_axis].Range.Min, gp.CurrentPlot->YAxis[y_axis].Range.Max, (float)t);
2020-05-03 01:24:10 -04:00
}
2020-05-16 22:09:36 -04:00
pix.x = (float)(gp.PixelRange[y_axis].Min.x + gp.Mx * (x - gp.CurrentPlot->XAxis.Range.Min));
pix.y = (float)(gp.PixelRange[y_axis].Min.y + gp.My[y_axis] * (y - gp.CurrentPlot->YAxis[y_axis].Range.Min));
2020-05-03 01:24:10 -04:00
return pix;
}
2020-05-15 09:05:02 -04:00
// This function is convenient but should not be used to process a high volume of points. Use the Transformer structs below instead.
2020-05-16 22:09:36 -04:00
ImVec2 PlotToPixels(const ImPlotPoint& plt, int y_axis) {
2020-05-11 07:12:22 -04:00
return PlotToPixels(plt.x, plt.y, y_axis);
2020-05-03 01:24:10 -04:00
}
//-----------------------------------------------------------------------------
2020-08-16 16:38:51 -04:00
// Item Utils
2020-05-03 01:24:10 -04:00
//-----------------------------------------------------------------------------
2020-08-17 21:20:15 -04:00
ImPlotItem* RegisterOrGetItem(const char* label_id) {
ImPlotContext& gp = *GImPlot;
2020-05-03 01:24:10 -04:00
ImGuiID id = ImGui::GetID(label_id);
ImPlotItem* item = gp.CurrentPlot->Items.GetOrAddByKey(id);
2020-06-12 23:02:43 -04:00
if (item->SeenThisFrame)
return item;
item->SeenThisFrame = true;
2020-05-03 01:24:10 -04:00
int idx = gp.CurrentPlot->Items.GetIndex(item);
item->ID = id;
2020-06-22 13:56:38 -04:00
if (ImGui::FindRenderedTextEnd(label_id, NULL) != label_id) {
gp.LegendIndices.push_back(idx);
item->NameOffset = gp.LegendLabels.size();
gp.LegendLabels.append(label_id, label_id + strlen(label_id) + 1);
}
else {
item->Show = true;
}
2020-05-03 01:24:10 -04:00
if (item->Show)
gp.VisibleItemCount++;
return item;
}
2020-08-16 16:38:51 -04:00
ImPlotItem* GetItem(int i) {
ImPlotContext& gp = *GImPlot;
2020-05-03 01:24:10 -04:00
return gp.CurrentPlot->Items.GetByIndex(gp.LegendIndices[i]);
}
2020-08-16 16:38:51 -04:00
ImPlotItem* GetItem(const char* label_id) {
ImPlotContext& gp = *GImPlot;
ImGuiID id = ImGui::GetID(label_id);
return gp.CurrentPlot->Items.GetByKey(id);
}
2020-08-16 16:38:51 -04:00
ImPlotItem* GetItem(const char* plot_title, const char* item_label_id) {
ImPlotState* plot = GetPlot(plot_title);
if (plot) {
ImGuiID id = ImGui::GetID(item_label_id);
return plot->Items.GetByKey(id);
}
return NULL;
}
2020-08-24 00:45:42 -04:00
void BustItemCache() {
ImPlotContext& gp = *GImPlot;
for (int p = 0; p < gp.Plots.GetSize(); ++p) {
ImPlotState& plot = *gp.Plots.GetByIndex(p);
2020-08-24 00:45:42 -04:00
plot.ColormapIdx = 0;
plot.Items.Clear();
}
}
2020-08-16 16:38:51 -04:00
//-----------------------------------------------------------------------------
// Legend Utils
//-----------------------------------------------------------------------------
int GetLegendCount() {
ImPlotContext& gp = *GImPlot;
return gp.LegendIndices.size();
}
2020-05-03 01:24:10 -04:00
const char* GetLegendLabel(int i) {
ImPlotContext& gp = *GImPlot;
2020-05-03 01:24:10 -04:00
ImPlotItem* item = gp.CurrentPlot->Items.GetByIndex(gp.LegendIndices[i]);
IM_ASSERT(item->NameOffset != -1 && item->NameOffset < gp.LegendLabels.Buf.Size);
return gp.LegendLabels.Buf.Data + item->NameOffset;
}
//-----------------------------------------------------------------------------
2020-04-27 11:27:59 -04:00
// Tick Utils
2020-05-03 01:24:10 -04:00
//-----------------------------------------------------------------------------
2020-04-27 11:27:59 -04:00
2020-08-25 22:59:43 -04:00
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);
2020-08-23 00:26:49 -04:00
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) {
2020-08-25 22:59:43 -04:00
if (range.Contains(major))
ticks.AddTick(major, true, true, LabelTickDefault);
for (int i = 1; i < nMinor; ++i) {
double minor = major + i * interval / nMinor;
2020-08-25 22:59:43 -04:00
if (range.Contains(minor))
ticks.AddTick(minor, false, true, LabelTickDefault);
}
2020-08-23 00:26:49 -04:00
}
}
2020-08-25 22:59:43 -04:00
void AddTicksLogarithmic(const ImPlotRange& range, int nMajor, ImPlotTickCollection& ticks) {
if (range.Min <= 0 || range.Max <= 0)
return;
double log_min = ImLog10(range.Min);
double log_max = ImLog10(range.Max);
int exp_step = ImMax(1,(int)(log_max - log_min) / nMajor);
int exp_min = (int)log_min;
int exp_max = (int)log_max;
if (exp_step != 1) {
while(exp_step % 3 != 0) exp_step++; // make step size multiple of three
while(exp_min % exp_step != 0) exp_min--; // decrease exp_min until exp_min + N * exp_step will be 0
}
for (int e = exp_min - exp_step; e < (exp_max + exp_step); e += exp_step) {
double major1 = ImPow(10, (double)(e));
double major2 = ImPow(10, (double)(e + 1));
double interval = (major2 - major1) / 9;
2020-08-25 22:59:43 -04:00
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) {
2020-04-27 11:27:59 -04:00
double minor = major1 + i * interval;
2020-08-25 22:59:43 -04:00
if (minor >= (range.Min - DBL_EPSILON) && minor <= (range.Max + DBL_EPSILON))
ticks.AddTick(minor, false, false, LabelTickScientific);
2020-08-23 00:26:49 -04:00
}
2020-04-27 11:27:59 -04:00
}
}
}
2020-08-25 22:59:43 -04:00
void AddTicksCustom(const double* values, const char** labels, int n, ImPlotTickCollection& ticks) {
for (int i = 0; i < n; ++i) {
2020-08-25 22:59:43 -04:00
ImPlotTick tick(values[i], false, true);
tick.BufferOffset = ticks.Labels.size();
if (labels != NULL) {
2020-08-25 22:59:43 -04:00
ticks.Labels.append(labels[i], labels[i] + strlen(labels[i]) + 1);
tick.LabelSize = ImGui::CalcTextSize(labels[i]);
}
2020-08-25 22:59:43 -04:00
ticks.AddTick(tick);
}
}
//-----------------------------------------------------------------------------
// Axis Utils
//-----------------------------------------------------------------------------
2020-08-25 22:59:43 -04:00
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;
}
2020-08-24 00:45:42 -04:00
void UpdateAxisColors(int axis_flag, ImPlotAxisColor* col) {
const ImVec4 col_label = GetStyleColorVec4(axis_flag);
const ImVec4 col_grid = GetStyleColorVec4(axis_flag + 1);
col->Major = ImGui::GetColorU32(col_grid);
col->Minor = ImGui::GetColorU32(col_grid*ImVec4(1,1,1,GImPlot->Style.MinorAlpha));
col->MajTxt = ImGui::GetColorU32(col_label);
col->MinTxt = ImGui::GetColorU32(col_label);
}
2020-08-24 00:45:42 -04:00
2020-05-03 01:24:10 -04:00
//-----------------------------------------------------------------------------
2020-04-27 11:27:59 -04:00
// BeginPlot()
2020-05-03 01:24:10 -04:00
//-----------------------------------------------------------------------------
2020-04-27 11:27:59 -04:00
bool BeginPlot(const char* title, const char* x_label, const char* y_label, const ImVec2& size, ImPlotFlags flags, ImPlotAxisFlags x_flags, ImPlotAxisFlags y_flags, ImPlotAxisFlags y2_flags, ImPlotAxisFlags y3_flags) {
2020-08-16 16:38:51 -04:00
IM_ASSERT_USER_ERROR(GImPlot != NULL, "No current context. Did you call ImPlot::CreateContext() or ImPlot::SetCurrentContext()?");
ImPlotContext& gp = *GImPlot;
2020-04-27 11:27:59 -04:00
IM_ASSERT_USER_ERROR(gp.CurrentPlot == NULL, "Mismatched BeginPlot()/EndPlot()!");
// FRONT MATTER -----------------------------------------------------------
ImGuiContext &G = *GImGui;
ImGuiWindow * Window = G.CurrentWindow;
if (Window->SkipItems) {
2020-08-16 16:38:51 -04:00
Reset(GImPlot);
2020-04-27 11:27:59 -04:00
return false;
}
const ImGuiID ID = Window->GetID(title);
const ImGuiStyle &Style = G.Style;
2020-05-13 10:11:25 -04:00
const ImGuiIO & IO = ImGui::GetIO();
2020-04-27 11:27:59 -04:00
2020-05-13 10:11:25 -04:00
bool just_created = gp.Plots.GetByKey(ID) == NULL;
gp.CurrentPlot = gp.Plots.GetOrAddByKey(ID);
2020-05-12 05:19:04 -04:00
ImPlotState &plot = *gp.CurrentPlot;
2020-04-27 11:27:59 -04:00
2020-05-11 07:12:22 -04:00
plot.CurrentYAxis = 0;
2020-04-27 11:27:59 -04:00
if (just_created) {
2020-05-11 07:12:22 -04:00
plot.Flags = flags;
plot.XAxis.Flags = x_flags;
plot.YAxis[0].Flags = y_flags;
plot.YAxis[1].Flags = y2_flags;
plot.YAxis[2].Flags = y3_flags;
2020-04-27 11:27:59 -04:00
}
2020-05-11 07:12:22 -04:00
else {
2020-05-13 10:11:25 -04:00
// TODO: Check which individual flags changed, and only reset those!
2020-05-11 07:12:22 -04:00
// There's probably an easy bit mask trick I'm not aware of.
2020-05-13 10:11:25 -04:00
if (flags != plot.PreviousFlags)
plot.Flags = flags;
2020-05-11 07:12:22 -04:00
if (y_flags != plot.YAxis[0].PreviousFlags)
plot.YAxis[0].Flags = y_flags;
2020-05-11 07:12:22 -04:00
if (y2_flags != plot.YAxis[1].PreviousFlags)
plot.YAxis[1].Flags = y2_flags;
2020-05-11 07:12:22 -04:00
if (y3_flags != plot.YAxis[2].PreviousFlags)
plot.YAxis[2].Flags = y3_flags;
2020-05-11 07:12:22 -04:00
}
plot.PreviousFlags = flags;
plot.XAxis.PreviousFlags = x_flags;
plot.YAxis[0].PreviousFlags = y_flags;
plot.YAxis[1].PreviousFlags = y2_flags;
plot.YAxis[2].PreviousFlags = y3_flags;
2020-04-27 11:27:59 -04:00
2020-05-03 01:24:10 -04:00
// capture scroll with a child region
2020-08-16 16:38:51 -04:00
if (!ImHasFlag(plot.Flags, ImPlotFlags_NoChild)) {
ImGui::BeginChild(title, ImVec2(size.x == 0 ? IMPLOT_DEFAULT_W : size.x, size.y == 0 ? IMPLOT_DEFAULT_H : size.y));
2020-05-03 01:24:10 -04:00
Window = ImGui::GetCurrentWindow();
Window->ScrollMax.y = 1.0f;
2020-06-03 15:37:01 -04:00
gp.ChildWindowMade = true;
}
else {
gp.ChildWindowMade = false;
2020-05-03 01:24:10 -04:00
}
ImDrawList &DrawList = *Window->DrawList;
2020-04-27 11:27:59 -04:00
// NextPlotData -----------------------------------------------------------
if (gp.NextPlotData.HasXRange) {
if (just_created || gp.NextPlotData.XRangeCond == ImGuiCond_Always) {
2020-05-11 07:12:22 -04:00
plot.XAxis.Range = gp.NextPlotData.X;
2020-04-27 11:27:59 -04:00
}
}
for (int i = 0; i < IMPLOT_Y_AXES; i++) {
2020-05-11 07:12:22 -04:00
if (gp.NextPlotData.HasYRange[i]) {
if (just_created || gp.NextPlotData.YRangeCond[i] == ImGuiCond_Always) {
2020-05-11 07:12:22 -04:00
plot.YAxis[i].Range = gp.NextPlotData.Y[i];
}
2020-04-27 11:27:59 -04:00
}
}
// AXIS STATES ------------------------------------------------------------
2020-08-19 12:34:52 -04:00
gp.X = ImPlotAxisState(&plot.XAxis, gp.NextPlotData.HasXRange, gp.NextPlotData.XRangeCond, true);
gp.Y[0] = ImPlotAxisState(&plot.YAxis[0], gp.NextPlotData.HasYRange[0], gp.NextPlotData.YRangeCond[0], true);
gp.Y[1] = ImPlotAxisState(&plot.YAxis[1], gp.NextPlotData.HasYRange[1], gp.NextPlotData.YRangeCond[1], ImHasFlag(plot.Flags, ImPlotFlags_YAxis2));
gp.Y[2] = ImPlotAxisState(&plot.YAxis[2], gp.NextPlotData.HasYRange[2], gp.NextPlotData.YRangeCond[2], ImHasFlag(plot.Flags, ImPlotFlags_YAxis3));
gp.LockPlot = gp.X.Lock && gp.Y[0].Lock && gp.Y[1].Lock && gp.Y[2].Lock;
2020-04-27 11:27:59 -04:00
// CONSTRAINTS ------------------------------------------------------------
2020-08-25 22:59:43 -04:00
ConstrainAxis(plot.XAxis);
for (int i = 0; i < IMPLOT_Y_AXES; i++)
ConstrainAxis(plot.YAxis[i]);
2020-04-27 11:27:59 -04:00
2020-08-24 00:45:42 -04:00
// AXIS COLORS -----------------------------------------------------------------
2020-04-27 11:27:59 -04:00
2020-08-24 00:45:42 -04:00
UpdateAxisColors(ImPlotCol_XAxis, &gp.Col_X);
UpdateAxisColors(ImPlotCol_YAxis, &gp.Col_Y[0]);
UpdateAxisColors(ImPlotCol_YAxis2, &gp.Col_Y[1]);
UpdateAxisColors(ImPlotCol_YAxis3, &gp.Col_Y[2]);
2020-04-27 11:27:59 -04:00
// BB AND HOVER -----------------------------------------------------------
// frame
ImVec2 frame_size = ImGui::CalcItemSize(size, IMPLOT_DEFAULT_W, IMPLOT_DEFAULT_H);
2020-08-24 00:45:42 -04:00
if (frame_size.x < gp.Style.PlotMinSize.x && size.x < 0.0f)
frame_size.x = gp.Style.PlotMinSize.x;
if (frame_size.y < gp.Style.PlotMinSize.y && size.y < 0.0f)
frame_size.y = gp.Style.PlotMinSize.y;
2020-04-27 11:27:59 -04:00
gp.BB_Frame = ImRect(Window->DC.CursorPos, Window->DC.CursorPos + frame_size);
2020-05-12 05:19:04 -04:00
ImGui::ItemSize(gp.BB_Frame);
if (!ImGui::ItemAdd(gp.BB_Frame, 0, &gp.BB_Frame)) {
2020-08-16 16:38:51 -04:00
Reset(GImPlot);
2020-04-27 11:27:59 -04:00
return false;
}
2020-05-12 05:19:04 -04:00
gp.Hov_Frame = ImGui::ItemHoverable(gp.BB_Frame, ID);
2020-08-24 00:45:42 -04:00
ImGui::RenderFrame(gp.BB_Frame.Min, gp.BB_Frame.Max, GetStyleColorU32(ImPlotCol_FrameBg), true, Style.FrameRounding);
2020-04-27 11:27:59 -04:00
// canvas bb
gp.BB_Canvas = ImRect(gp.BB_Frame.Min + gp.Style.PlotPadding, gp.BB_Frame.Max - gp.Style.PlotPadding);
2020-04-27 11:27:59 -04:00
2020-08-16 16:38:51 -04:00
gp.RenderX = (ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_GridLines) ||
ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_TickMarks) ||
ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_TickLabels));
for (int i = 0; i < IMPLOT_Y_AXES; i++) {
2020-05-11 07:12:22 -04:00
gp.RenderY[i] =
gp.Y[i].Present &&
2020-08-16 16:38:51 -04:00
(ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_GridLines) ||
ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_TickMarks) ||
ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_TickLabels));
2020-05-11 07:12:22 -04:00
}
2020-04-27 11:27:59 -04:00
// get ticks
if (gp.RenderX && gp.NextPlotData.ShowDefaultTicksX) {
if (ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_LogScale))
AddTicksLogarithmic(plot.XAxis.Range, (int)(gp.BB_Canvas.GetWidth() * 0.01f), gp.XTicks);
else
AddTicksDefault(plot.XAxis.Range, ImMax(2, (int)IM_ROUND(0.003 * gp.BB_Canvas.GetWidth())), IMPLOT_SUB_DIV, gp.XTicks);
}
for (int i = 0; i < IMPLOT_Y_AXES; i++) {
2020-06-03 15:37:01 -04:00
if (gp.RenderY[i] && gp.NextPlotData.ShowDefaultTicksY[i]) {
if (ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_LogScale))
AddTicksLogarithmic(plot.YAxis[i].Range, (int)(gp.BB_Canvas.GetHeight() * 0.02f) ,gp.YTicks[i]);
else
AddTicksDefault(plot.YAxis[i].Range, ImMax(2, (int)IM_ROUND(0.003 * gp.BB_Canvas.GetHeight())), IMPLOT_SUB_DIV, gp.YTicks[i]);
2020-05-11 07:12:22 -04:00
}
}
2020-04-27 11:27:59 -04:00
2020-08-19 12:34:52 -04:00
// plot bb
2020-05-12 05:19:04 -04:00
const ImVec2 title_size = ImGui::CalcTextSize(title, NULL, true);
const float txt_height = ImGui::GetTextLineHeight();
2020-08-24 00:45:42 -04:00
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)
2020-08-25 22:59:43 -04:00
+ (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)
2020-08-24 00:45:42 -04:00
+ ((gp.Y[1].Present && gp.Y[2].Present) ? gp.Style.LabelPadding.x + gp.Style.MinorTickLen.y : 0)
2020-08-25 22:59:43 -04:00
+ ((gp.Y[2].Present && gp.Y[2].HasLabels) ? gp.YTicks[2].MaxWidth + gp.Style.LabelPadding.x : 0);
2020-08-19 12:34:52 -04:00
gp.BB_Plot = ImRect(gp.BB_Canvas.Min + ImVec2(pad_left, pad_top), gp.BB_Canvas.Max - ImVec2(pad_right, pad_bot));
gp.Hov_Plot = gp.BB_Plot.Contains(IO.MousePos);
2020-04-27 11:27:59 -04:00
2020-08-19 12:34:52 -04:00
// x axis region bb and hover
const ImRect xAxisRegion_bb(gp.BB_Plot.GetBL(), ImVec2(gp.BB_Plot.Max.x, gp.BB_Frame.Max.y));
plot.XAxis.HoveredExt = xAxisRegion_bb.Contains(IO.MousePos);
plot.XAxis.HoveredTot = plot.XAxis.HoveredExt || gp.Hov_Plot;
2020-05-11 07:12:22 -04:00
2020-08-19 12:34:52 -04:00
// axis label reference
gp.YAxisReference[0] = gp.BB_Plot.Min.x;
gp.YAxisReference[1] = gp.BB_Plot.Max.x;
2020-08-25 22:59:43 -04:00
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);
2020-08-19 12:34:52 -04:00
// y axis regions bb and hover
ImRect yAxisRegion_bb[IMPLOT_Y_AXES];
2020-08-19 12:34:52 -04:00
yAxisRegion_bb[0] = ImRect(ImVec2(gp.BB_Frame.Min.x, gp.BB_Plot.Min.y), ImVec2(gp.BB_Plot.Min.x, gp.BB_Plot.Max.y));
2020-08-23 00:26:49 -04:00
yAxisRegion_bb[1] = gp.Y[2].Present
? ImRect(gp.BB_Plot.GetTR(), ImVec2(gp.YAxisReference[2], gp.BB_Plot.Max.y))
2020-08-19 12:34:52 -04:00
: ImRect(gp.BB_Plot.GetTR(), ImVec2(gp.BB_Frame.Max.x, gp.BB_Plot.Max.y));
2020-08-23 00:26:49 -04:00
2020-08-19 12:34:52 -04:00
yAxisRegion_bb[2] = ImRect(ImVec2(gp.YAxisReference[2], gp.BB_Plot.Min.y), ImVec2(gp.BB_Frame.Max.x, gp.BB_Plot.Max.y));
2020-05-11 07:12:22 -04:00
2020-08-19 12:34:52 -04:00
for (int i = 0; i < IMPLOT_Y_AXES; ++i) {
plot.YAxis[i].HoveredExt = gp.Y[i].Present && yAxisRegion_bb[i].Contains(IO.MousePos);
plot.YAxis[i].HoveredTot = plot.YAxis[i].HoveredExt || gp.Hov_Plot;
}
2020-05-13 10:11:25 -04:00
2020-08-19 12:34:52 -04:00
#if 0
ImGui::GetForegroundDrawList()->AddRect(gp.BB_Canvas.Min, gp.BB_Canvas.Max, IM_COL32_WHITE);
ImGui::GetForegroundDrawList()->AddRectFilled(xAxisRegion_bb.Min, xAxisRegion_bb.Max, IM_COL32(255,0,0,plot.XAxis.HoveredTot ? 128 : 64));
ImGui::GetForegroundDrawList()->AddRectFilled(yAxisRegion_bb[0].Min, yAxisRegion_bb[0].Max, IM_COL32(255,255,0,plot.YAxis[0].HoveredTot ? 128 : 64));
if (gp.Y[1].Present)
ImGui::GetForegroundDrawList()->AddRectFilled(yAxisRegion_bb[1].Min, yAxisRegion_bb[1].Max, IM_COL32(0,255,0,plot.YAxis[1].HoveredTot ? 128 : 64));
if (gp.Y[2].Present)
ImGui::GetForegroundDrawList()->AddRectFilled(yAxisRegion_bb[2].Min, yAxisRegion_bb[2].Max, IM_COL32(0,0,255,plot.YAxis[2].HoveredTot ? 128 : 64));
#endif
2020-08-19 12:34:52 -04:00
const bool any_hov_y_axis_region = plot.YAxis[0].HoveredTot || plot.YAxis[1].HoveredTot || plot.YAxis[2].HoveredTot;
2020-04-27 11:27:59 -04:00
// legend hovered from last frame
2020-08-16 16:38:51 -04:00
const bool hov_legend = ImHasFlag(plot.Flags, ImPlotFlags_Legend) ? gp.Hov_Frame && plot.BB_Legend.Contains(IO.MousePos) : false;
2020-04-30 09:45:03 -04:00
bool hov_query = false;
if (gp.Hov_Frame && gp.Hov_Plot && plot.Queried && !plot.Querying) {
2020-05-11 07:12:22 -04:00
ImRect bb_query = plot.QueryRect;
bb_query.Min += gp.BB_Plot.Min;
bb_query.Max += gp.BB_Plot.Min;
2020-05-11 07:12:22 -04:00
2020-04-30 09:45:03 -04:00
hov_query = bb_query.Contains(IO.MousePos);
}
// QUERY DRAG -------------------------------------------------------------
if (plot.DraggingQuery && (IO.MouseReleased[gp.InputMap.PanButton] || !IO.MouseDown[gp.InputMap.PanButton])) {
2020-04-30 09:45:03 -04:00
plot.DraggingQuery = false;
}
2020-05-13 10:11:25 -04:00
if (plot.DraggingQuery) {
2020-05-12 05:19:04 -04:00
ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeAll);
2020-05-11 07:12:22 -04:00
plot.QueryRect.Min += IO.MouseDelta;
plot.QueryRect.Max += IO.MouseDelta;
2020-04-30 09:45:03 -04:00
}
if (gp.Hov_Frame && gp.Hov_Plot && hov_query && !plot.DraggingQuery && !plot.Selecting && !hov_legend) {
2020-05-12 05:19:04 -04:00
ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeAll);
2020-05-11 07:12:22 -04:00
const bool any_y_dragging = plot.YAxis[0].Dragging || plot.YAxis[1].Dragging || plot.YAxis[2].Dragging;
if (IO.MouseDown[gp.InputMap.PanButton] && !plot.XAxis.Dragging && !any_y_dragging) {
2020-04-30 09:45:03 -04:00
plot.DraggingQuery = true;
2020-05-13 10:11:25 -04:00
}
}
2020-04-27 11:27:59 -04:00
// DRAG INPUT -------------------------------------------------------------
// end drags
if (plot.XAxis.Dragging && (IO.MouseReleased[gp.InputMap.PanButton] || !IO.MouseDown[gp.InputMap.PanButton])) {
2020-04-27 11:27:59 -04:00
plot.XAxis.Dragging = false;
2020-05-13 10:11:25 -04:00
G.IO.MouseDragMaxDistanceSqr[0] = 0;
2020-04-27 11:27:59 -04:00
}
for (int i = 0; i < IMPLOT_Y_AXES; i++) {
if (plot.YAxis[i].Dragging && (IO.MouseReleased[gp.InputMap.PanButton] || !IO.MouseDown[gp.InputMap.PanButton])) {
plot.YAxis[i].Dragging = false;
2020-05-11 07:12:22 -04:00
G.IO.MouseDragMaxDistanceSqr[0] = 0;
}
2020-04-27 11:27:59 -04:00
}
2020-05-11 07:12:22 -04:00
const bool any_y_dragging = plot.YAxis[0].Dragging || plot.YAxis[1].Dragging || plot.YAxis[2].Dragging;
2020-05-11 09:57:36 -04:00
bool drag_in_progress = plot.XAxis.Dragging || any_y_dragging;
2020-04-27 11:27:59 -04:00
// do drag
2020-05-11 07:12:22 -04:00
if (drag_in_progress) {
2020-05-03 01:24:10 -04:00
UpdateTransformCache();
if (!gp.X.Lock && plot.XAxis.Dragging) {
ImPlotPoint plot_tl = PixelsToPlot(gp.BB_Plot.Min - IO.MouseDelta, 0);
ImPlotPoint plot_br = PixelsToPlot(gp.BB_Plot.Max - IO.MouseDelta, 0);
if (!gp.X.LockMin)
plot.XAxis.Range.Min = gp.X.Invert ? plot_br.x : plot_tl.x;
if (!gp.X.LockMax)
plot.XAxis.Range.Max = gp.X.Invert ? plot_tl.x : plot_br.x;
2020-05-11 07:12:22 -04:00
}
for (int i = 0; i < IMPLOT_Y_AXES; i++) {
if (!gp.Y[i].Lock && plot.YAxis[i].Dragging) {
ImPlotPoint plot_tl = PixelsToPlot(gp.BB_Plot.Min - IO.MouseDelta, i);
ImPlotPoint plot_br = PixelsToPlot(gp.BB_Plot.Max - IO.MouseDelta, i);
if (!gp.Y[i].LockMin)
plot.YAxis[i].Range.Min = gp.Y[i].Invert ? plot_tl.y : plot_br.y;
if (!gp.Y[i].LockMax)
plot.YAxis[i].Range.Max = gp.Y[i].Invert ? plot_br.y : plot_tl.y;
2020-05-11 07:12:22 -04:00
}
}
// Set the mouse cursor based on which axes are moving.
int direction = 0;
if (!gp.X.Lock && plot.XAxis.Dragging) {
2020-05-11 07:12:22 -04:00
direction |= (1 << 1);
}
for (int i = 0; i < IMPLOT_Y_AXES; i++) {
if (!gp.Y[i].Present) { continue; }
if (!gp.Y[i].Lock && plot.YAxis[i].Dragging) {
2020-05-11 07:12:22 -04:00
direction |= (1 << 2);
break;
}
}
if (IO.MouseDragMaxDistanceSqr[0] > 5) {
2020-08-23 00:26:49 -04:00
if (direction == 0)
ImGui::SetMouseCursor(ImGuiMouseCursor_NotAllowed);
else if (direction == (1 << 1))
ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeEW);
else if (direction == (1 << 2))
ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeNS);
else
ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeAll);
2020-05-11 07:12:22 -04:00
}
2020-04-27 11:27:59 -04:00
}
// start drag
2020-08-16 16:38:51 -04:00
if (!drag_in_progress && gp.Hov_Frame && IO.MouseClicked[gp.InputMap.PanButton] && ImHasFlag(IO.KeyMods, gp.InputMap.PanMod) && !plot.Selecting && !hov_legend && !hov_query && !plot.DraggingQuery) {
2020-08-19 12:34:52 -04:00
if (plot.XAxis.HoveredTot) {
2020-05-11 07:12:22 -04:00
plot.XAxis.Dragging = true;
}
for (int i = 0; i < IMPLOT_Y_AXES; i++) {
2020-08-19 12:34:52 -04:00
if (plot.YAxis[i].HoveredTot) {
2020-05-11 07:12:22 -04:00
plot.YAxis[i].Dragging = true;
}
}
}
2020-04-27 11:27:59 -04:00
// SCROLL INPUT -----------------------------------------------------------
2020-08-19 12:34:52 -04:00
if (gp.Hov_Frame && (plot.XAxis.HoveredTot || any_hov_y_axis_region) && IO.MouseWheel != 0) {
2020-05-03 01:24:10 -04:00
UpdateTransformCache();
float zoom_rate = IMPLOT_ZOOM_RATE;
2020-05-13 10:11:25 -04:00
if (IO.MouseWheel > 0)
zoom_rate = (-zoom_rate) / (1.0f + (2.0f * zoom_rate));
2020-08-16 16:38:51 -04:00
float tx = ImRemap(IO.MousePos.x, gp.BB_Plot.Min.x, gp.BB_Plot.Max.x, 0.0f, 1.0f);
float ty = ImRemap(IO.MousePos.y, gp.BB_Plot.Min.y, gp.BB_Plot.Max.y, 0.0f, 1.0f);
2020-08-19 12:34:52 -04:00
if (plot.XAxis.HoveredTot && !gp.X.Lock) {
2020-05-16 22:09:36 -04:00
ImPlotAxisScale axis_scale(0, tx, ty, zoom_rate);
const ImPlotPoint& plot_tl = axis_scale.Min;
const ImPlotPoint& plot_br = axis_scale.Max;
2020-05-11 07:12:22 -04:00
if (!gp.X.LockMin)
plot.XAxis.Range.Min = gp.X.Invert ? plot_br.x : plot_tl.x;
if (!gp.X.LockMax)
plot.XAxis.Range.Max = gp.X.Invert ? plot_tl.x : plot_br.x;
2020-05-11 07:12:22 -04:00
}
for (int i = 0; i < IMPLOT_Y_AXES; i++) {
2020-08-19 12:34:52 -04:00
if (plot.YAxis[i].HoveredTot && !gp.Y[i].Lock) {
2020-05-16 22:09:36 -04:00
ImPlotAxisScale axis_scale(i, tx, ty, zoom_rate);
const ImPlotPoint& plot_tl = axis_scale.Min;
const ImPlotPoint& plot_br = axis_scale.Max;
if (!gp.Y[i].LockMin)
plot.YAxis[i].Range.Min = gp.Y[i].Invert ? plot_tl.y : plot_br.y;
if (!gp.Y[i].LockMax)
plot.YAxis[i].Range.Max = gp.Y[i].Invert ? plot_br.y : plot_tl.y;
2020-05-11 07:12:22 -04:00
}
2020-05-13 10:11:25 -04:00
}
2020-04-27 11:27:59 -04:00
}
2020-04-28 21:17:26 -04:00
// BOX-SELECTION AND QUERY ------------------------------------------------
2020-04-27 11:27:59 -04:00
// confirm selection
if (plot.Selecting && (IO.MouseReleased[gp.InputMap.BoxSelectButton] || !IO.MouseDown[gp.InputMap.BoxSelectButton])) {
2020-05-03 01:24:10 -04:00
UpdateTransformCache();
2020-04-28 21:17:26 -04:00
ImVec2 select_size = plot.SelectStart - IO.MousePos;
2020-08-16 16:38:51 -04:00
if (ImHasFlag(plot.Flags, ImPlotFlags_BoxSelect) && ImFabs(select_size.x) > 2 && ImFabs(select_size.y) > 2) {
2020-05-16 22:09:36 -04:00
ImPlotPoint p1 = PixelsToPlot(plot.SelectStart);
ImPlotPoint p2 = PixelsToPlot(IO.MousePos);
2020-06-15 20:54:58 -04:00
if (!gp.X.LockMin && IO.KeyMods != gp.InputMap.HorizontalMod)
2020-05-11 07:12:22 -04:00
plot.XAxis.Range.Min = ImMin(p1.x, p2.x);
2020-06-15 20:54:58 -04:00
if (!gp.X.LockMax && IO.KeyMods != gp.InputMap.HorizontalMod)
2020-05-11 07:12:22 -04:00
plot.XAxis.Range.Max = ImMax(p1.x, p2.x);
for (int i = 0; i < IMPLOT_Y_AXES; i++) {
2020-05-11 07:12:22 -04:00
p1 = PixelsToPlot(plot.SelectStart, i);
p2 = PixelsToPlot(IO.MousePos, i);
2020-06-15 20:54:58 -04:00
if (!gp.Y[i].LockMin && IO.KeyMods != gp.InputMap.VerticalMod)
2020-05-11 07:12:22 -04:00
plot.YAxis[i].Range.Min = ImMin(p1.y, p2.y);
2020-06-15 20:54:58 -04:00
if (!gp.Y[i].LockMax && IO.KeyMods != gp.InputMap.VerticalMod)
2020-05-11 07:12:22 -04:00
plot.YAxis[i].Range.Max = ImMax(p1.y, p2.y);
}
2020-05-13 10:11:25 -04:00
}
2020-04-27 11:27:59 -04:00
plot.Selecting = false;
}
// bad selection
2020-08-16 16:38:51 -04:00
if (plot.Selecting && (!ImHasFlag(plot.Flags, ImPlotFlags_BoxSelect) || gp.LockPlot) && ImLengthSqr(plot.SelectStart - IO.MousePos) > 4) {
2020-04-27 11:27:59 -04:00
ImGui::SetMouseCursor(ImGuiMouseCursor_NotAllowed);
}
// cancel selection
2020-06-15 20:54:58 -04:00
if (plot.Selecting && (IO.MouseClicked[gp.InputMap.BoxSelectCancelButton] || IO.MouseDown[gp.InputMap.BoxSelectCancelButton])) {
2020-04-27 11:27:59 -04:00
plot.Selecting = false;
}
// begin selection or query
2020-08-16 16:38:51 -04:00
if (gp.Hov_Frame && gp.Hov_Plot && IO.MouseClicked[gp.InputMap.BoxSelectButton] && ImHasFlag(IO.KeyMods, gp.InputMap.BoxSelectMod)) {
2020-04-27 11:27:59 -04:00
plot.SelectStart = IO.MousePos;
2020-04-28 21:17:26 -04:00
plot.Selecting = true;
}
// update query
if (plot.Querying) {
2020-05-03 01:24:10 -04:00
UpdateTransformCache();
2020-08-16 16:38:51 -04:00
plot.QueryRect.Min.x = ImHasFlag(IO.KeyMods, gp.InputMap.HorizontalMod) ? gp.BB_Plot.Min.x : ImMin(plot.QueryStart.x, IO.MousePos.x);
plot.QueryRect.Max.x = ImHasFlag(IO.KeyMods, gp.InputMap.HorizontalMod) ? gp.BB_Plot.Max.x : ImMax(plot.QueryStart.x, IO.MousePos.x);
plot.QueryRect.Min.y = ImHasFlag(IO.KeyMods, gp.InputMap.VerticalMod) ? gp.BB_Plot.Min.y : ImMin(plot.QueryStart.y, IO.MousePos.y);
plot.QueryRect.Max.y = ImHasFlag(IO.KeyMods, gp.InputMap.VerticalMod) ? gp.BB_Plot.Max.y : ImMax(plot.QueryStart.y, IO.MousePos.y);
2020-05-11 07:12:22 -04:00
plot.QueryRect.Min -= gp.BB_Plot.Min;
plot.QueryRect.Max -= gp.BB_Plot.Min;
2020-04-28 21:17:26 -04:00
}
// end query
2020-06-15 20:54:58 -04:00
if (plot.Querying && (IO.MouseReleased[gp.InputMap.QueryButton] || IO.MouseReleased[gp.InputMap.BoxSelectButton])) {
2020-04-28 21:17:26 -04:00
plot.Querying = false;
2020-08-23 00:26:49 -04:00
if (plot.QueryRect.GetWidth() > 2 && plot.QueryRect.GetHeight() > 2)
plot.Queried = true;
else
plot.Queried = false;
}
// begin query
2020-08-16 16:38:51 -04:00
if (ImHasFlag(plot.Flags, ImPlotFlags_Query) && gp.Hov_Frame && gp.Hov_Plot && IO.MouseClicked[gp.InputMap.QueryButton] && ImHasFlag(IO.KeyMods, gp.InputMap.QueryMod)) {
2020-04-28 21:17:26 -04:00
plot.QueryRect = ImRect(0,0,0,0);
plot.Querying = true;
plot.Queried = true;
plot.QueryStart = IO.MousePos;
}
// toggle between select/query
2020-08-16 16:38:51 -04:00
if (ImHasFlag(plot.Flags, ImPlotFlags_Query) && plot.Selecting && ImHasFlag(IO.KeyMods,gp.InputMap.QueryToggleMod)) {
2020-04-28 21:17:26 -04:00
plot.Selecting = false;
plot.QueryRect = ImRect(0,0,0,0);
plot.Querying = true;
2020-04-28 21:17:26 -04:00
plot.Queried = true;
plot.QueryStart = plot.SelectStart;
}
2020-08-16 16:38:51 -04:00
if (ImHasFlag(plot.Flags, ImPlotFlags_BoxSelect) && plot.Querying && !ImHasFlag(IO.KeyMods, gp.InputMap.QueryToggleMod) && !IO.MouseDown[gp.InputMap.QueryButton]) {
2020-04-28 21:17:26 -04:00
plot.Selecting = true;
plot.Querying = false;
plot.Queried = false;
plot.QueryRect = ImRect(0,0,0,0);
2020-04-27 11:27:59 -04:00
}
2020-08-19 12:43:00 -04:00
if (!ImHasFlag(plot.Flags, ImPlotFlags_Query)) {
plot.Queried = false;
plot.Querying = false;
plot.QueryRect = ImRect(0,0,0,0);
}
2020-05-13 10:11:25 -04:00
2020-08-20 00:50:12 -04:00
// FIT -----------------------------------------------------------
2020-04-27 11:27:59 -04:00
2020-08-20 00:50:12 -04:00
// fit from double click
if ( IO.MouseDoubleClicked[gp.InputMap.FitButton] && gp.Hov_Frame && (plot.XAxis.HoveredTot || any_hov_y_axis_region) && !hov_legend && !hov_query ) {
2020-04-27 11:27:59 -04:00
gp.FitThisFrame = true;
2020-08-19 12:34:52 -04:00
gp.FitX = plot.XAxis.HoveredTot;
2020-08-23 00:26:49 -04:00
for (int i = 0; i < IMPLOT_Y_AXES; i++)
gp.FitY[i] = plot.YAxis[i].HoveredTot;
}
2020-08-20 00:50:12 -04:00
// fit from FitNextPlotAxes
if (gp.NextPlotData.FitX) {
gp.FitThisFrame = true;
gp.FitX = true;
}
for (int i = 0; i < IMPLOT_Y_AXES; ++i) {
if (gp.NextPlotData.FitY[i]) {
gp.FitThisFrame = true;
gp.FitY[i] = true;
}
}
2020-04-27 11:27:59 -04:00
// FOCUS ------------------------------------------------------------------
// focus window
2020-06-15 20:54:58 -04:00
if ((IO.MouseClicked[0] || IO.MouseClicked[1] || IO.MouseClicked[2]) && gp.Hov_Frame)
2020-05-13 10:11:25 -04:00
ImGui::FocusWindow(ImGui::GetCurrentWindow());
2020-04-27 11:27:59 -04:00
2020-05-03 01:24:10 -04:00
UpdateTransformCache();
2020-04-27 11:27:59 -04:00
// set mouse position
for (int i = 0; i < IMPLOT_Y_AXES; i++) {
gp.MousePos[i] = PixelsToPlot(IO.MousePos, i);
2020-05-11 07:12:22 -04:00
}
2020-04-27 11:27:59 -04:00
// RENDER -----------------------------------------------------------------
// grid bg
2020-08-24 00:45:42 -04:00
DrawList.AddRectFilled(gp.BB_Plot.Min, gp.BB_Plot.Max, GetStyleColorU32(ImPlotCol_PlotBg));
2020-04-27 11:27:59 -04:00
// render axes
2020-05-03 01:24:10 -04:00
PushPlotClipRect();
2020-04-27 11:27:59 -04:00
2020-08-25 22:59:43 -04:00
// transform ticks (TODO: Move this into ImPlotTickCollection)
2020-04-27 11:27:59 -04:00
if (gp.RenderX) {
for (int t = 0; t < gp.XTicks.Size; t++) {
2020-08-25 22:59:43 -04:00
ImPlotTick *xt = &gp.XTicks.Ticks[t];
2020-05-29 13:39:30 -04:00
xt->PixelPos = PlotToPixels(xt->PlotPos, 0, 0).x;
}
2020-04-27 11:27:59 -04:00
}
for (int i = 0; i < IMPLOT_Y_AXES; i++) {
2020-05-11 07:12:22 -04:00
if (gp.RenderY[i]) {
for (int t = 0; t < gp.YTicks[i].Size; t++) {
2020-08-25 22:59:43 -04:00
ImPlotTick *yt = &gp.YTicks[i].Ticks[t];
2020-05-16 22:53:59 -04:00
yt->PixelPos = PlotToPixels(0, yt->PlotPos, i).y;
}
2020-05-11 07:12:22 -04:00
}
2020-04-27 11:27:59 -04:00
}
// render grid
2020-08-16 16:38:51 -04:00
if (ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_GridLines)) {
float density = gp.XTicks.Size / gp.BB_Plot.GetWidth();
ImVec4 col_min = ImGui::ColorConvertU32ToFloat4(gp.Col_X.Minor);
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++) {
2020-08-25 22:59:43 -04:00
ImPlotTick& xt = gp.XTicks.Ticks[t];
if (xt.Major)
2020-08-24 00:45:42 -04:00
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);
2020-08-23 00:26:49 -04:00
else if (density < 0.2f)
2020-08-24 00:45:42 -04:00
DrawList.AddLine(ImVec2(xt.PixelPos, gp.BB_Plot.Min.y), ImVec2(xt.PixelPos, gp.BB_Plot.Max.y), col_min32, gp.Style.MinorGridSize.x);
}
2020-04-27 11:27:59 -04:00
}
for (int i = 0; i < IMPLOT_Y_AXES; i++) {
2020-08-16 16:38:51 -04:00
if (gp.Y[i].Present && ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_GridLines)) {
float density = gp.YTicks[i].Size / gp.BB_Plot.GetHeight();
ImVec4 col_min = ImGui::ColorConvertU32ToFloat4(gp.Col_Y[i].Minor);
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++) {
2020-08-25 22:59:43 -04:00
ImPlotTick& yt = gp.YTicks[i].Ticks[t];
if (yt.Major)
2020-08-24 00:45:42 -04:00
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)
2020-08-24 00:45:42 -04:00
DrawList.AddLine(ImVec2(gp.BB_Plot.Min.x, yt.PixelPos), ImVec2(gp.BB_Plot.Max.x, yt.PixelPos), col_min32, gp.Style.MinorGridSize.y);
}
2020-05-11 07:12:22 -04:00
}
2020-04-27 11:27:59 -04:00
}
2020-05-03 01:24:10 -04:00
PopPlotClipRect();
2020-04-27 11:27:59 -04:00
// render title
if (title_size.x > 0.0f) {
2020-08-24 00:45:42 -04:00
ImU32 col = GetStyleColorU32(ImPlotCol_TitleText);
const char* title_end = ImGui::FindRenderedTextEnd(title, NULL);
DrawList.AddText(ImVec2(gp.BB_Canvas.GetCenter().x - title_size.x * 0.5f, gp.BB_Canvas.Min.y),col,title,title_end);
2020-04-27 11:27:59 -04:00
}
// render axis labels
if (x_label) {
const ImVec2 xLabel_size = ImGui::CalcTextSize(x_label);
const ImVec2 xLabel_pos(gp.BB_Plot.GetCenter().x - xLabel_size.x * 0.5f, gp.BB_Canvas.Max.y - txt_height);
DrawList.AddText(xLabel_pos, gp.Col_X.MajTxt, x_label);
}
if (y_label) {
const ImVec2 yLabel_size = CalcTextSizeVertical(y_label);
const ImVec2 yLabel_pos(gp.BB_Canvas.Min.x, gp.BB_Plot.GetCenter().y + yLabel_size.y * 0.5f);
2020-08-24 09:51:03 -04:00
AddTextVertical(&DrawList, yLabel_pos, gp.Col_Y[0].MajTxt, y_label);
}
// render tick labels
ImGui::PushClipRect(gp.BB_Frame.Min, gp.BB_Frame.Max, true);
2020-08-16 16:38:51 -04:00
if (ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_TickLabels)) {
for (int t = 0; t < gp.XTicks.Size; t++) {
2020-08-25 22:59:43 -04:00
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)
2020-08-25 22:59:43 -04:00
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));
2020-04-27 11:27:59 -04:00
}
2020-05-11 07:12:22 -04:00
}
for (int i = 0; i < IMPLOT_Y_AXES; i++) {
2020-08-16 16:38:51 -04:00
if (gp.Y[i].Present && ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_TickLabels)) {
for (int t = 0; t < gp.YTicks[i].Size; t++) {
2020-08-25 22:59:43 -04:00
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);
2020-08-25 22:59:43 -04:00
DrawList.AddText(start, yt->Major ? gp.Col_Y[i].MajTxt : gp.Col_Y[i].MinTxt, gp.YTicks[i].GetLabel(t));
2020-05-11 07:12:22 -04:00
}
}
2020-04-27 11:27:59 -04:00
}
}
2020-05-12 05:19:04 -04:00
ImGui::PopClipRect();
2020-04-27 11:27:59 -04:00
// push plot ID into stack
2020-05-12 05:19:04 -04:00
ImGui::PushID(ID);
2020-04-27 11:27:59 -04:00
return true;
}
2020-05-03 01:24:10 -04:00
//-----------------------------------------------------------------------------
2020-04-27 11:27:59 -04:00
// Context Menu
2020-05-03 01:24:10 -04:00
//-----------------------------------------------------------------------------
2020-04-27 11:27:59 -04:00
2020-05-17 00:25:15 -04:00
template <typename F>
2020-06-02 23:07:27 -04:00
bool DragFloat(const char* label, F* v, float v_speed, F v_min, F v_max) {
2020-05-17 00:25:15 -04:00
return false;
}
template <>
2020-06-02 23:07:27 -04:00
bool DragFloat<double>(const char* label, double* v, float v_speed, double v_min, double v_max) {
2020-05-17 00:25:15 -04:00
return ImGui::DragScalar(label, ImGuiDataType_Double, v, v_speed, &v_min, &v_max, "%.3f", 1);
}
2020-05-16 22:09:36 -04:00
2020-05-17 00:25:15 -04:00
template <>
2020-06-02 23:07:27 -04:00
bool DragFloat<float>(const char* label, float* v, float v_speed, float v_min, float v_max) {
2020-05-17 00:25:15 -04:00
return ImGui::DragScalar(label, ImGuiDataType_Float, v, v_speed, &v_min, &v_max, "%.3f", 1);
2020-05-16 22:09:36 -04:00
}
inline void BeginDisabledControls(bool cond) {
if (cond) {
2020-04-27 11:27:59 -04:00
ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true);
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.25f);
}
}
2020-04-27 11:27:59 -04:00
inline void EndDisabledControls(bool cond) {
if (cond) {
2020-04-27 11:27:59 -04:00
ImGui::PopItemFlag();
ImGui::PopStyleVar();
}
}
2020-08-19 02:18:05 -04:00
inline void ShowAxisContextMenu(ImPlotAxisState& state) {
ImGui::PushItemWidth(75);
bool total_lock = state.HasRange && state.RangeCond == ImGuiCond_Always;
2020-08-16 16:38:51 -04:00
bool logscale = ImHasFlag(state.Axis->Flags, ImPlotAxisFlags_LogScale);
bool grid = ImHasFlag(state.Axis->Flags, ImPlotAxisFlags_GridLines);
bool ticks = ImHasFlag(state.Axis->Flags, ImPlotAxisFlags_TickMarks);
bool labels = ImHasFlag(state.Axis->Flags, ImPlotAxisFlags_TickLabels);
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.
2020-08-24 12:06:43 -04:00
BeginDisabledControls(total_lock);
if (ImGui::Checkbox("##LockMin", &state.LockMin))
2020-08-16 16:38:51 -04:00
ImFlipFlag(state.Axis->Flags, ImPlotAxisFlags_LockMin);
EndDisabledControls(total_lock);
2020-04-27 11:27:59 -04:00
ImGui::SameLine();
BeginDisabledControls(state.LockMin);
DragFloat("Min", &state.Axis->Range.Min, (float)drag_speed, -HUGE_VAL, state.Axis->Range.Max - DBL_EPSILON);
EndDisabledControls(state.LockMin);
2020-04-27 11:27:59 -04:00
BeginDisabledControls(total_lock);
if (ImGui::Checkbox("##LockMax", &state.LockMax))
2020-08-16 16:38:51 -04:00
ImFlipFlag(state.Axis->Flags, ImPlotAxisFlags_LockMax);
EndDisabledControls(total_lock);
2020-04-27 11:27:59 -04:00
ImGui::SameLine();
BeginDisabledControls(state.LockMax);
DragFloat("Max", &state.Axis->Range.Max, (float)drag_speed, state.Axis->Range.Min + DBL_EPSILON, HUGE_VAL);
EndDisabledControls(state.LockMax);
2020-04-27 11:27:59 -04:00
ImGui::Separator();
if (ImGui::Checkbox("Invert", &state.Invert))
2020-08-16 16:38:51 -04:00
ImFlipFlag(state.Axis->Flags, ImPlotAxisFlags_Invert);
2020-04-27 11:27:59 -04:00
if (ImGui::Checkbox("Log Scale", &logscale))
2020-08-16 16:38:51 -04:00
ImFlipFlag(state.Axis->Flags, ImPlotAxisFlags_LogScale);
2020-04-27 11:27:59 -04:00
ImGui::Separator();
if (ImGui::Checkbox("Grid Lines", &grid))
2020-08-16 16:38:51 -04:00
ImFlipFlag(state.Axis->Flags, ImPlotAxisFlags_GridLines);
2020-04-27 11:27:59 -04:00
if (ImGui::Checkbox("Tick Marks", &ticks))
2020-08-16 16:38:51 -04:00
ImFlipFlag(state.Axis->Flags, ImPlotAxisFlags_TickMarks);
2020-04-27 11:27:59 -04:00
if (ImGui::Checkbox("Labels", &labels))
2020-08-16 16:38:51 -04:00
ImFlipFlag(state.Axis->Flags, ImPlotAxisFlags_TickLabels);
2020-04-27 11:27:59 -04:00
}
2020-08-19 02:18:05 -04:00
void ShowPlotContextMenu(ImPlotState& plot) {
ImPlotContext& gp = *GImPlot;
2020-05-13 10:11:25 -04:00
if (ImGui::BeginMenu("X-Axis")) {
ImGui::PushID("X");
2020-08-19 02:18:05 -04:00
ShowAxisContextMenu(gp.X);
2020-05-12 05:19:04 -04:00
ImGui::PopID();
2020-04-27 11:27:59 -04:00
ImGui::EndMenu();
}
for (int i = 0; i < IMPLOT_Y_AXES; i++) {
2020-08-16 16:38:51 -04:00
if (i == 1 && !ImHasFlag(plot.Flags, ImPlotFlags_YAxis2)) {
2020-05-11 07:12:22 -04:00
continue;
}
2020-08-16 16:38:51 -04:00
if (i == 2 && !ImHasFlag(plot.Flags, ImPlotFlags_YAxis3)) {
2020-05-11 07:12:22 -04:00
continue;
}
char buf[10] = {};
if (i == 0) {
snprintf(buf, sizeof(buf) - 1, "Y-Axis");
} else {
snprintf(buf, sizeof(buf) - 1, "Y-Axis %d", i + 1);
}
if (ImGui::BeginMenu(buf)) {
2020-05-13 10:11:25 -04:00
ImGui::PushID(i);
2020-08-19 02:18:05 -04:00
ShowAxisContextMenu(gp.Y[i]);
2020-05-12 05:19:04 -04:00
ImGui::PopID();
2020-05-11 07:12:22 -04:00
ImGui::EndMenu();
}
2020-04-27 11:27:59 -04:00
}
2020-05-13 10:11:25 -04:00
2020-04-27 11:27:59 -04:00
ImGui::Separator();
if ((ImGui::BeginMenu("Settings"))) {
2020-08-16 16:38:51 -04:00
if (ImGui::MenuItem("Box Select",NULL,ImHasFlag(plot.Flags, ImPlotFlags_BoxSelect))) {
ImFlipFlag(plot.Flags, ImPlotFlags_BoxSelect);
2020-05-12 05:19:04 -04:00
}
2020-08-16 16:38:51 -04:00
if (ImGui::MenuItem("Query",NULL,ImHasFlag(plot.Flags, ImPlotFlags_Query))) {
ImFlipFlag(plot.Flags, ImPlotFlags_Query);
2020-04-27 11:27:59 -04:00
}
2020-08-16 16:38:51 -04:00
if (ImGui::MenuItem("Crosshairs",NULL,ImHasFlag(plot.Flags, ImPlotFlags_Crosshairs))) {
ImFlipFlag(plot.Flags, ImPlotFlags_Crosshairs);
2020-04-27 11:27:59 -04:00
}
2020-08-16 16:38:51 -04:00
if (ImGui::MenuItem("Mouse Position",NULL,ImHasFlag(plot.Flags, ImPlotFlags_MousePos))) {
ImFlipFlag(plot.Flags, ImPlotFlags_MousePos);
2020-04-27 11:27:59 -04:00
}
2020-08-16 16:38:51 -04:00
if (ImGui::MenuItem("Anti-Aliased Lines",NULL,ImHasFlag(plot.Flags, ImPlotFlags_AntiAliased))) {
ImFlipFlag(plot.Flags, ImPlotFlags_AntiAliased);
2020-04-27 11:27:59 -04:00
}
ImGui::EndMenu();
}
2020-08-16 16:38:51 -04:00
if (ImGui::MenuItem("Legend",NULL,ImHasFlag(plot.Flags, ImPlotFlags_Legend))) {
ImFlipFlag(plot.Flags, ImPlotFlags_Legend);
2020-04-27 11:27:59 -04:00
}
2020-08-25 22:59:43 -04:00
#ifdef IMPLOT_DEBUG
if (ImGui::BeginMenu("Debug")) {
ImGui::PushItemWidth(50);
2020-04-27 11:27:59 -04:00
ImGui::LabelText("Plots", "%d", gp.Plots.GetSize());
2020-08-25 22:59:43 -04:00
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());
2020-04-27 11:27:59 -04:00
ImGui::PopItemWidth();
ImGui::EndMenu();
}
#endif
}
2020-05-03 01:24:10 -04:00
//-----------------------------------------------------------------------------
2020-04-27 11:27:59 -04:00
// EndPlot()
2020-05-03 01:24:10 -04:00
//-----------------------------------------------------------------------------
2020-04-27 11:27:59 -04:00
void EndPlot() {
2020-08-16 16:38:51 -04:00
IM_ASSERT_USER_ERROR(GImPlot != NULL, "No current context. Did you call ImPlot::CreateContext() or ImPlot::SetCurrentContext()?");
ImPlotContext& gp = *GImPlot;
2020-05-13 10:11:25 -04:00
IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "Mismatched BeginPlot()/EndPlot()!");
ImGuiContext &G = *GImGui;
ImPlotState &plot = *gp.CurrentPlot;
ImGuiWindow * Window = G.CurrentWindow;
2020-04-27 11:27:59 -04:00
ImDrawList & DrawList = *Window->DrawList;
const ImGuiIO & IO = ImGui::GetIO();
2020-04-27 11:27:59 -04:00
// AXIS STATES ------------------------------------------------------------
const bool any_y_locked = gp.Y[0].Lock || gp.Y[1].Present ? gp.Y[1].Lock : false || gp.Y[2].Present ? gp.Y[2].Lock : false;
2020-05-11 07:12:22 -04:00
const bool any_y_dragging = plot.YAxis[0].Dragging || plot.YAxis[1].Dragging || plot.YAxis[2].Dragging;
2020-04-27 11:27:59 -04:00
2020-06-03 15:37:01 -04:00
2020-04-27 11:27:59 -04:00
// FINAL RENDER -----------------------------------------------------------
2020-04-28 21:17:26 -04:00
// render ticks
2020-05-11 07:12:22 -04:00
PushPlotClipRect();
2020-08-16 16:38:51 -04:00
if (ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_TickMarks)) {
for (int t = 0; t < gp.XTicks.Size; t++) {
2020-08-25 22:59:43 -04:00
ImPlotTick *xt = &gp.XTicks.Ticks[t];
2020-08-24 00:45:42 -04:00
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,
xt->Major ? gp.Style.MajorTickSize.x : gp.Style.MinorTickSize.x);
}
2020-04-28 21:17:26 -04:00
}
2020-05-11 07:12:22 -04:00
PopPlotClipRect();
ImGui::PushClipRect(gp.BB_Plot.Min, ImVec2(gp.BB_Frame.Max.x, gp.BB_Plot.Max.y), true);
2020-05-11 07:12:22 -04:00
int axis_count = 0;
for (int i = 0; i < IMPLOT_Y_AXES; i++) {
if (!gp.Y[i].Present) { continue; }
2020-05-11 07:12:22 -04:00
axis_count++;
2020-08-19 12:34:52 -04:00
float x_start = gp.YAxisReference[i];
2020-08-16 16:38:51 -04:00
if (ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_TickMarks)) {
2020-07-26 22:28:22 -04:00
float direction = (i == 0) ? 1.0f : -1.0f;
bool no_major = axis_count >= 3;
for (int t = 0; t < gp.YTicks[i].Size; t++) {
2020-08-25 22:59:43 -04:00
ImPlotTick *yt = &gp.YTicks[i].Ticks[t];
2020-07-26 22:28:22 -04:00
ImVec2 start = ImVec2(x_start, yt->PixelPos);
2020-08-24 00:45:42 -04:00
DrawList.AddLine(start,
start + ImVec2(direction * ((!no_major && yt->Major) ? gp.Style.MajorTickLen.y : gp.Style.MinorTickLen.y), 0),
gp.Col_Y[i].Major,
(!no_major && yt->Major) ? gp.Style.MajorTickSize.y : gp.Style.MinorTickSize.y);
2020-07-26 22:28:22 -04:00
}
2020-05-11 07:12:22 -04:00
}
if (axis_count >= 3) {
// Draw a bar next to the ticks to act as a visual separator.
DrawList.AddLine(
ImVec2(x_start, gp.BB_Plot.Min.y),
ImVec2(x_start, gp.BB_Plot.Max.y),
2020-08-24 00:45:42 -04:00
GetStyleColorU32(ImPlotCol_PlotBorder), 1);
2020-05-11 07:12:22 -04:00
}
2020-04-28 21:17:26 -04:00
}
2020-05-12 05:19:04 -04:00
ImGui::PopClipRect();
2020-05-11 07:12:22 -04:00
2020-08-16 16:38:51 -04:00
// render y-axis drag/drop hover
2020-08-19 12:34:52 -04:00
if ((gp.Y[1].Present || gp.Y[2].Present) && ImGui::IsDragDropPayloadBeingAccepted()) {
for (int i = 0; i < IMPLOT_Y_AXES; ++i) {
if (plot.YAxis[i].HoveredExt) {
float x_loc = gp.YAxisReference[i];
ImVec2 p1(x_loc - 5, gp.BB_Plot.Min.y - 5);
ImVec2 p2(x_loc + 5, gp.BB_Plot.Max.y + 5);
DrawList.AddRect(p1, p2, ImGui::GetColorU32(ImGuiCol_DragDropTarget), 0.0f, ImDrawCornerFlags_All, 2.0f);
2020-07-26 22:28:22 -04:00
}
2020-08-23 00:26:49 -04:00
}
2020-07-26 22:28:22 -04:00
}
2020-05-11 07:12:22 -04:00
PushPlotClipRect();
2020-04-28 21:17:26 -04:00
// render selection/query
if (plot.Selecting) {
ImRect select_bb(ImMin(IO.MousePos, plot.SelectStart), ImMax(IO.MousePos, plot.SelectStart));
2020-08-24 00:45:42 -04:00
const bool select_big_enough = ImLengthSqr(select_bb.GetSize()) > 4;
2020-08-16 16:38:51 -04:00
if (plot.Selecting && !gp.LockPlot && ImHasFlag(plot.Flags, ImPlotFlags_BoxSelect) && select_big_enough) {
2020-08-24 00:45:42 -04:00
const ImVec4 col = GetStyleColorVec4(ImPlotCol_Selection);
const ImU32 col_bg = ImGui::GetColorU32(col * ImVec4(1,1,1,0.25f));
const ImU32 col_bd = ImGui::GetColorU32(col);
2020-06-03 15:37:01 -04:00
if (IO.KeyAlt && IO.KeyShift) {
2020-08-24 00:45:42 -04:00
DrawList.AddRectFilled(gp.BB_Plot.Min, gp.BB_Plot.Max, col_bg);
DrawList.AddRect( gp.BB_Plot.Min, gp.BB_Plot.Max, col_bd);
2020-04-28 21:17:26 -04:00
}
else if ((gp.X.Lock || IO.KeyAlt)) {
2020-08-24 00:45:42 -04:00
DrawList.AddRectFilled(ImVec2(gp.BB_Plot.Min.x, select_bb.Min.y), ImVec2(gp.BB_Plot.Max.x, select_bb.Max.y), col_bg);
DrawList.AddRect( ImVec2(gp.BB_Plot.Min.x, select_bb.Min.y), ImVec2(gp.BB_Plot.Max.x, select_bb.Max.y), col_bd);
2020-04-28 21:17:26 -04:00
}
2020-06-03 15:37:01 -04:00
else if ((any_y_locked || IO.KeyShift)) {
2020-08-24 00:45:42 -04:00
DrawList.AddRectFilled(ImVec2(select_bb.Min.x, gp.BB_Plot.Min.y), ImVec2(select_bb.Max.x, gp.BB_Plot.Max.y), col_bg);
DrawList.AddRect( ImVec2(select_bb.Min.x, gp.BB_Plot.Min.y), ImVec2(select_bb.Max.x, gp.BB_Plot.Max.y), col_bd);
2020-04-28 21:17:26 -04:00
}
2020-06-03 15:37:01 -04:00
else {
2020-08-24 00:45:42 -04:00
DrawList.AddRectFilled(select_bb.Min, select_bb.Max, col_bg);
DrawList.AddRect( select_bb.Min, select_bb.Max, col_bd);
2020-04-28 21:17:26 -04:00
}
}
}
if (ImHasFlag(plot.Flags, ImPlotFlags_Query)) // draw query rect only when query enabled.
{
2020-08-24 00:45:42 -04:00
const ImVec4 col = GetStyleColorVec4(ImPlotCol_Query);
const ImU32 col_bd = ImGui::GetColorU32(col * ImVec4(1,1,1,0.25f));
const ImU32 col_bg = ImGui::GetColorU32(col);
if (plot.Querying || plot.Queried) {
if (plot.QueryRect.GetWidth() > 2 && plot.QueryRect.GetHeight() > 2) {
2020-08-24 00:45:42 -04:00
DrawList.AddRectFilled(plot.QueryRect.Min + gp.BB_Plot.Min, plot.QueryRect.Max + gp.BB_Plot.Min, col_bd);
DrawList.AddRect( plot.QueryRect.Min + gp.BB_Plot.Min, plot.QueryRect.Max + gp.BB_Plot.Min, col_bg);
}
2020-05-13 10:11:25 -04:00
}
else if (plot.Queried) {
ImRect bb_query = plot.QueryRect;
bb_query.Min += gp.BB_Plot.Min;
bb_query.Max += gp.BB_Plot.Min;
2020-08-24 00:45:42 -04:00
DrawList.AddRectFilled(bb_query.Min, bb_query.Max, col_bd);
DrawList.AddRect( bb_query.Min, bb_query.Max, col_bg);
}
2020-05-11 07:12:22 -04:00
}
2020-04-27 11:27:59 -04:00
// render legend
2020-05-12 05:19:04 -04:00
const float txt_ht = ImGui::GetTextLineHeight();
2020-08-24 00:45:42 -04:00
const ImVec2 legend_offset = gp.Style.LegendPadding;
const ImVec2 legend_spacing(5, 5);
2020-04-27 11:27:59 -04:00
const float legend_icon_size = txt_ht;
ImRect legend_content_bb;
2020-05-03 01:24:10 -04:00
int nItems = GetLegendCount();
2020-04-27 11:27:59 -04:00
bool hov_legend = false;
2020-08-16 16:38:51 -04:00
if (ImHasFlag(plot.Flags, ImPlotFlags_Legend) && nItems > 0) {
2020-04-27 11:27:59 -04:00
// get max width
float max_label_width = 0;
for (int i = 0; i < nItems; ++i) {
2020-05-03 01:24:10 -04:00
const char* label = GetLegendLabel(i);
2020-05-12 05:19:04 -04:00
ImVec2 labelWidth = ImGui::CalcTextSize(label, NULL, true);
2020-04-27 11:27:59 -04:00
max_label_width = labelWidth.x > max_label_width ? labelWidth.x : max_label_width;
}
legend_content_bb = ImRect(gp.BB_Plot.Min + legend_offset, gp.BB_Plot.Min + legend_offset + ImVec2(max_label_width, nItems * txt_ht));
2020-08-24 00:45:42 -04:00
plot.BB_Legend = ImRect(legend_content_bb.Min, legend_content_bb.Max + legend_spacing * 2 + ImVec2(legend_icon_size, 0));
2020-08-16 16:38:51 -04:00
hov_legend = ImHasFlag(plot.Flags, ImPlotFlags_Legend) ? gp.Hov_Frame && plot.BB_Legend.Contains(IO.MousePos) : false;
2020-04-27 11:27:59 -04:00
// render legend box
2020-08-24 00:45:42 -04:00
ImU32 col_bg = GetStyleColorU32(ImPlotCol_LegendBg);
ImU32 col_bd = GetStyleColorU32(ImPlotCol_LegendBorder);
ImVec4 col_txt = GetStyleColorVec4(ImPlotCol_LegendText);
ImU32 col_txt_dis = ImGui::GetColorU32(col_txt * ImVec4(1,1,1,0.25f));
DrawList.AddRectFilled(plot.BB_Legend.Min, plot.BB_Legend.Max, col_bg);
DrawList.AddRect(plot.BB_Legend.Min, plot.BB_Legend.Max, col_bd);
2020-04-27 11:27:59 -04:00
// render each legend item
for (int i = 0; i < nItems; ++i) {
2020-08-16 16:38:51 -04:00
ImPlotItem* item = GetItem(i);
2020-04-27 11:27:59 -04:00
ImRect icon_bb;
2020-08-24 00:45:42 -04:00
icon_bb.Min = legend_content_bb.Min + legend_spacing + ImVec2(0, i * txt_ht) + ImVec2(2, 2);
icon_bb.Max = legend_content_bb.Min + legend_spacing + ImVec2(0, i * txt_ht) + ImVec2(legend_icon_size - 2, legend_icon_size - 2);
2020-04-28 01:38:52 -04:00
ImRect label_bb;
2020-08-24 00:45:42 -04:00
label_bb.Min = legend_content_bb.Min + legend_spacing + ImVec2(0, i * txt_ht) + ImVec2(2, 2);
label_bb.Max = legend_content_bb.Min + legend_spacing + ImVec2(0, i * txt_ht) + ImVec2(legend_content_bb.Max.x, legend_icon_size - 2);
2020-04-28 01:38:52 -04:00
ImU32 col_hl_txt;
2020-08-16 16:38:51 -04:00
if (ImHasFlag(plot.Flags, ImPlotFlags_Highlight) && hov_legend && (icon_bb.Contains(IO.MousePos) || label_bb.Contains(IO.MousePos))) {
2020-04-28 01:38:52 -04:00
item->Highlight = true;
2020-08-24 00:45:42 -04:00
col_hl_txt = ImGui::GetColorU32(ImLerp(col_txt, item->Color, 0.25f));
2020-04-28 01:38:52 -04:00
}
else
{
item->Highlight = false;
2020-08-24 00:45:42 -04:00
col_hl_txt = ImGui::GetColorU32(col_txt);
}
2020-04-27 11:27:59 -04:00
ImU32 iconColor;
if (hov_legend && icon_bb.Contains(IO.MousePos)) {
2020-05-11 07:12:22 -04:00
ImVec4 colAlpha = item->Color;
2020-04-27 11:27:59 -04:00
colAlpha.w = 0.5f;
2020-05-12 05:19:04 -04:00
iconColor = item->Show ? ImGui::GetColorU32(colAlpha)
: ImGui::GetColorU32(ImGuiCol_TextDisabled, 0.5f);
2020-04-27 11:27:59 -04:00
if (IO.MouseClicked[0])
item->Show = !item->Show;
} else {
2020-08-24 00:45:42 -04:00
iconColor = item->Show ? ImGui::GetColorU32(item->Color) : col_txt_dis;
2020-04-27 11:27:59 -04:00
}
DrawList.AddRectFilled(icon_bb.Min, icon_bb.Max, iconColor, 1);
2020-05-03 01:24:10 -04:00
const char* label = GetLegendLabel(i);
2020-05-12 05:19:04 -04:00
const char* text_display_end = ImGui::FindRenderedTextEnd(label, NULL);
2020-04-27 11:27:59 -04:00
if (label != text_display_end)
2020-08-24 00:45:42 -04:00
DrawList.AddText(legend_content_bb.Min + legend_spacing + ImVec2(legend_icon_size, i * txt_ht), item->Show ? col_hl_txt : col_txt_dis, label, text_display_end);
2020-04-27 11:27:59 -04:00
}
}
// render crosshairs
2020-08-16 16:38:51 -04:00
if (ImHasFlag(plot.Flags, ImPlotFlags_Crosshairs) && gp.Hov_Plot && gp.Hov_Frame &&
2020-05-11 07:12:22 -04:00
!(plot.XAxis.Dragging || any_y_dragging) && !plot.Selecting && !plot.Querying && !hov_legend) {
2020-04-27 11:27:59 -04:00
ImGui::SetMouseCursor(ImGuiMouseCursor_None);
ImVec2 xy = IO.MousePos;
ImVec2 h1(gp.BB_Plot.Min.x, xy.y);
2020-04-27 11:27:59 -04:00
ImVec2 h2(xy.x - 5, xy.y);
ImVec2 h3(xy.x + 5, xy.y);
ImVec2 h4(gp.BB_Plot.Max.x, xy.y);
ImVec2 v1(xy.x, gp.BB_Plot.Min.y);
2020-04-27 11:27:59 -04:00
ImVec2 v2(xy.x, xy.y - 5);
ImVec2 v3(xy.x, xy.y + 5);
ImVec2 v4(xy.x, gp.BB_Plot.Max.y);
2020-08-24 00:45:42 -04:00
ImU32 col = GetStyleColorU32(ImPlotCol_Crosshairs);
DrawList.AddLine(h1, h2, col);
DrawList.AddLine(h3, h4, col);
DrawList.AddLine(v1, v2, col);
DrawList.AddLine(v3, v4, col);
2020-04-27 11:27:59 -04:00
}
// render mouse pos
2020-08-16 16:38:51 -04:00
if (ImHasFlag(plot.Flags, ImPlotFlags_MousePos) && gp.Hov_Plot) {
char buffer[128] = {};
2020-08-16 16:38:51 -04:00
ImBufferWriter writer(buffer, sizeof(buffer));
2020-05-11 07:12:22 -04:00
// x
2020-08-23 00:26:49 -04:00
if (ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_LogScale)) {
writer.Write("%.3E", gp.MousePos[0].x);
}
else {
2020-08-25 22:59:43 -04:00
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
2020-08-23 00:26:49 -04:00
if (ImHasFlag(plot.YAxis[0].Flags, ImPlotAxisFlags_LogScale)) {
writer.Write(",%.3E", gp.MousePos[0].y);
}
else {
2020-08-25 22:59:43 -04:00
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
2020-08-16 16:38:51 -04:00
if (ImHasFlag(plot.Flags, ImPlotFlags_YAxis2)) {
2020-08-23 00:26:49 -04:00
if (ImHasFlag(plot.YAxis[1].Flags, ImPlotAxisFlags_LogScale)) {
writer.Write(",(%.3E)", gp.MousePos[1].y);
}
else {
2020-08-25 22:59:43 -04:00
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);
}
2020-05-11 07:12:22 -04:00
}
// y3
2020-08-16 16:38:51 -04:00
if (ImHasFlag(plot.Flags, ImPlotFlags_YAxis3)) {
2020-08-23 00:26:49 -04:00
if (ImHasFlag(plot.YAxis[2].Flags, ImPlotAxisFlags_LogScale)) {
writer.Write(",(%.3E)", gp.MousePos[2].y);
}
else {
2020-08-25 22:59:43 -04:00
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);
}
2020-05-11 07:12:22 -04:00
}
2020-05-12 05:19:04 -04:00
ImVec2 size = ImGui::CalcTextSize(buffer);
2020-08-24 00:45:42 -04:00
ImVec2 pos = gp.BB_Plot.Max - size - gp.Style.InfoPadding;
DrawList.AddText(pos, GetStyleColorU32(ImPlotCol_InlayText), buffer);
2020-04-27 11:27:59 -04:00
}
2020-05-03 01:24:10 -04:00
PopPlotClipRect();
2020-04-27 11:27:59 -04:00
// render border
2020-08-24 00:45:42 -04:00
if (gp.Style.PlotBorderSize > 0)
DrawList.AddRect(gp.BB_Plot.Min, gp.BB_Plot.Max, GetStyleColorU32(ImPlotCol_PlotBorder), 0, ImDrawCornerFlags_All, gp.Style.PlotBorderSize);
2020-04-27 11:27:59 -04:00
// FIT DATA --------------------------------------------------------------
2020-04-28 21:17:26 -04:00
if (gp.FitThisFrame && (gp.VisibleItemCount > 0 || plot.Queried)) {
2020-08-16 16:38:51 -04:00
if (gp.FitX && !ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_LockMin) && !NanOrInf(gp.ExtentsX.Min)) {
2020-05-11 07:12:22 -04:00
plot.XAxis.Range.Min = gp.ExtentsX.Min;
}
2020-08-16 16:38:51 -04:00
if (gp.FitX && !ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_LockMax) && !NanOrInf(gp.ExtentsX.Max)) {
2020-05-11 07:12:22 -04:00
plot.XAxis.Range.Max = gp.ExtentsX.Max;
}
for (int i = 0; i < IMPLOT_Y_AXES; i++) {
2020-08-16 16:38:51 -04:00
if (gp.FitY[i] && !ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_LockMin) && !NanOrInf(gp.ExtentsY[i].Min)) {
2020-05-11 07:12:22 -04:00
plot.YAxis[i].Range.Min = gp.ExtentsY[i].Min;
}
2020-08-16 16:38:51 -04:00
if (gp.FitY[i] && !ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_LockMax) && !NanOrInf(gp.ExtentsY[i].Max)) {
2020-05-11 07:12:22 -04:00
plot.YAxis[i].Range.Max = gp.ExtentsY[i].Max;
}
}
2020-04-27 11:27:59 -04:00
}
2020-08-19 02:18:05 -04:00
// CONTEXT MENUS -----------------------------------------------------------
2020-04-27 11:27:59 -04:00
2020-08-16 16:38:51 -04:00
if (ImHasFlag(plot.Flags, ImPlotFlags_ContextMenu) && gp.Hov_Frame && gp.Hov_Plot && IO.MouseDoubleClicked[gp.InputMap.ContextMenuButton] && !hov_legend)
2020-08-19 02:18:05 -04:00
ImGui::OpenPopup("##PlotContext");
if (ImGui::BeginPopup("##PlotContext")) {
ShowPlotContextMenu(plot);
2020-04-27 11:27:59 -04:00
ImGui::EndPopup();
}
2020-08-19 02:18:05 -04:00
2020-08-23 00:26:49 -04:00
if (ImHasFlag(plot.Flags, ImPlotFlags_ContextMenu) && gp.Hov_Frame && plot.XAxis.HoveredExt && IO.MouseDoubleClicked[gp.InputMap.ContextMenuButton] && !hov_legend)
ImGui::OpenPopup("##XContext");
2020-08-19 02:18:05 -04:00
if (ImGui::BeginPopup("##XContext")) {
ImGui::Text("X-Axis"); ImGui::Separator();
ShowAxisContextMenu(gp.X);
ImGui::EndPopup();
}
for (int i = 0; i < IMPLOT_Y_AXES; ++i) {
ImGui::PushID(i);
2020-08-23 00:26:49 -04:00
if (ImHasFlag(plot.Flags, ImPlotFlags_ContextMenu) && gp.Hov_Frame && plot.YAxis[i].HoveredExt && IO.MouseDoubleClicked[gp.InputMap.ContextMenuButton] && !hov_legend)
ImGui::OpenPopup("##YContext");
2020-08-19 02:18:05 -04:00
if (ImGui::BeginPopup("##YContext")) {
if (i == 0) {
ImGui::Text("Y-Axis"); ImGui::Separator();
}
else {
ImGui::Text("Y-Axis %d", i + 1); ImGui::Separator();
}
ShowAxisContextMenu(gp.Y[i]);
ImGui::EndPopup();
}
ImGui::PopID();
}
2020-04-27 11:27:59 -04:00
// CLEANUP ----------------------------------------------------------------
2020-06-12 23:02:43 -04:00
// reset the plot items for the next frame
for (int i = 0; i < gp.CurrentPlot->Items.GetSize(); ++i) {
gp.CurrentPlot->Items.GetByIndex(i)->SeenThisFrame = false;
}
2020-05-12 05:19:04 -04:00
// Pop ImGui::PushID at the end of BeginPlot
2020-05-13 10:11:25 -04:00
ImGui::PopID();
2020-06-03 15:37:01 -04:00
// Reset context for next plot
2020-08-16 16:38:51 -04:00
Reset(GImPlot);
2020-04-27 11:27:59 -04:00
}
2020-05-03 01:24:10 -04:00
//-----------------------------------------------------------------------------
2020-04-27 11:27:59 -04:00
// MISC API
2020-05-03 01:24:10 -04:00
//-----------------------------------------------------------------------------
2020-04-27 11:27:59 -04:00
2020-08-16 16:38:51 -04:00
ImPlotInputMap& GetInputMap() {
return GImPlot->InputMap;
}
2020-05-29 13:39:30 -04:00
void SetNextPlotLimits(double x_min, double x_max, double y_min, double y_max, ImGuiCond cond) {
2020-08-16 19:48:09 -04:00
IM_ASSERT_USER_ERROR(GImPlot->CurrentPlot == NULL, "SetNextPlotLimits() needs to be called before BeginPlot()!");
2020-05-11 07:12:22 -04:00
SetNextPlotLimitsX(x_min, x_max, cond);
SetNextPlotLimitsY(y_min, y_max, cond);
2020-04-27 11:27:59 -04:00
}
2020-05-29 13:39:30 -04:00
void SetNextPlotLimitsX(double x_min, double x_max, ImGuiCond cond) {
ImPlotContext& gp = *GImPlot;
2020-06-03 15:37:01 -04:00
IM_ASSERT_USER_ERROR(gp.CurrentPlot == NULL, "SetNextPlotLSetNextPlotLimitsXimitsY() needs to be called before BeginPlot()!");
2020-04-27 11:27:59 -04:00
IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
gp.NextPlotData.HasXRange = true;
gp.NextPlotData.XRangeCond = cond;
2020-05-11 07:12:22 -04:00
gp.NextPlotData.X.Min = x_min;
gp.NextPlotData.X.Max = x_max;
2020-04-27 11:27:59 -04:00
}
2020-05-29 13:39:30 -04:00
void SetNextPlotLimitsY(double y_min, double y_max, ImGuiCond cond, int y_axis) {
ImPlotContext& gp = *GImPlot;
2020-06-03 15:37:01 -04:00
IM_ASSERT_USER_ERROR(gp.CurrentPlot == NULL, "SetNextPlotLimitsY() 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");
2020-04-27 11:27:59 -04:00
IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
2020-05-11 07:12:22 -04:00
gp.NextPlotData.HasYRange[y_axis] = true;
gp.NextPlotData.YRangeCond[y_axis] = cond;
gp.NextPlotData.Y[y_axis].Min = y_min;
gp.NextPlotData.Y[y_axis].Max = y_max;
}
2020-08-20 00:50:12 -04:00
void FitNextPlotAxes(bool x, bool y, bool y2, bool y3) {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot == NULL, "FitNextPlotAxes() needs to be called before BeginPlot()!");
gp.NextPlotData.FitX = x;
gp.NextPlotData.FitY[0] = y;
gp.NextPlotData.FitY[1] = y2;
gp.NextPlotData.FitY[2] = y3;
}
2020-06-03 15:37:01 -04:00
void SetNextPlotTicksX(const double* values, int n_ticks, const char** labels, bool show_default) {
ImPlotContext& gp = *GImPlot;
2020-06-03 15:37:01 -04:00
IM_ASSERT_USER_ERROR(gp.CurrentPlot == NULL, "SetNextPlotTicksX() needs to be called before BeginPlot()!");
gp.NextPlotData.ShowDefaultTicksX = show_default;
2020-08-25 22:59:43 -04:00
AddTicksCustom(values, labels, n_ticks, gp.XTicks);
2020-06-03 15:37:01 -04:00
}
void SetNextPlotTicksX(double x_min, double x_max, int n_ticks, const char** labels, bool show_default) {
IM_ASSERT_USER_ERROR(n_ticks > 1, "The number of ticks must be greater than 1");
static ImVector<double> buffer;
FillRange(buffer, n_ticks, x_min, x_max);
SetNextPlotTicksX(&buffer[0], n_ticks, labels, show_default);
}
void SetNextPlotTicksY(const double* values, int n_ticks, const char** labels, bool show_default, int y_axis) {
ImPlotContext& gp = *GImPlot;
2020-06-03 15:37:01 -04:00
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");
2020-06-03 15:37:01 -04:00
gp.NextPlotData.ShowDefaultTicksY[y_axis] = show_default;
2020-08-25 22:59:43 -04:00
AddTicksCustom(values, labels, n_ticks, gp.YTicks[y_axis]);
2020-06-03 15:37:01 -04:00
}
void SetNextPlotTicksY(double y_min, double y_max, int n_ticks, const char** labels, bool show_default, int y_axis) {
IM_ASSERT_USER_ERROR(n_ticks > 1, "The number of ticks must be greater than 1");
static ImVector<double> buffer;
FillRange(buffer, n_ticks, y_min, y_max);
SetNextPlotTicksY(&buffer[0], n_ticks, labels, show_default,y_axis);
}
2020-05-11 07:12:22 -04:00
void SetPlotYAxis(int y_axis) {
ImPlotContext& gp = *GImPlot;
2020-06-03 15:37:01 -04:00
IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "SetPlotYAxis() needs to be called between BeginPlot() and EndPlot()!");
IM_ASSERT_USER_ERROR(y_axis >= 0 && y_axis < IMPLOT_Y_AXES, "y_axis needs to be between 0 and IMPLOT_Y_AXES");
2020-05-11 07:12:22 -04:00
gp.CurrentPlot->CurrentYAxis = y_axis;
2020-04-27 11:27:59 -04:00
}
2020-04-30 09:45:03 -04:00
ImVec2 GetPlotPos() {
ImPlotContext& gp = *GImPlot;
2020-06-03 15:37:01 -04:00
IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "GetPlotPos() needs to be called between BeginPlot() and EndPlot()!");
return gp.BB_Plot.Min;
2020-04-30 09:45:03 -04:00
}
ImVec2 GetPlotSize() {
ImPlotContext& gp = *GImPlot;
2020-06-03 15:37:01 -04:00
IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "GetPlotSize() needs to be called between BeginPlot() and EndPlot()!");
return gp.BB_Plot.GetSize();
2020-04-30 09:45:03 -04:00
}
void PushPlotClipRect() {
ImPlotContext& gp = *GImPlot;
2020-06-03 15:37:01 -04:00
IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "PushPlotClipRect() needs to be called between BeginPlot() and EndPlot()!");
ImGui::PushClipRect(gp.BB_Plot.Min, gp.BB_Plot.Max, true);
2020-04-30 09:45:03 -04:00
}
void PopPlotClipRect() {
2020-05-12 05:19:04 -04:00
ImGui::PopClipRect();
2020-04-30 09:45:03 -04:00
}
2020-05-13 10:11:25 -04:00
bool IsPlotHovered() {
ImPlotContext& gp = *GImPlot;
2020-06-03 15:37:01 -04:00
IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "IsPlotHovered() needs to be called between BeginPlot() and EndPlot()!");
return gp.Hov_Frame && gp.Hov_Plot;
2020-04-28 21:17:26 -04:00
}
bool IsPlotXAxisHovered() {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "IsPlotXAxisHovered() needs to be called between BeginPlot() and EndPlot()!");
2020-08-19 12:34:52 -04:00
return gp.CurrentPlot->XAxis.HoveredExt;
}
bool IsPlotYAxisHovered(int y_axis_in) {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(y_axis_in >= -1 && y_axis_in < IMPLOT_Y_AXES, "y_axis needs to between -1 and IMPLOT_Y_AXES");
IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "IsPlotYAxisHovered() needs to be called between BeginPlot() and EndPlot()!");
const int y_axis = y_axis_in >= 0 ? y_axis_in : gp.CurrentPlot->CurrentYAxis;
2020-08-19 12:34:52 -04:00
return gp.CurrentPlot->YAxis[y_axis].HoveredExt;
}
2020-05-16 22:09:36 -04:00
ImPlotPoint GetPlotMousePos(int y_axis_in) {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(y_axis_in >= -1 && y_axis_in < IMPLOT_Y_AXES, "y_axis needs to between -1 and IMPLOT_Y_AXES");
2020-06-03 15:37:01 -04:00
IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "GetPlotMousePos() needs to be called between BeginPlot() and EndPlot()!");
2020-05-11 07:12:22 -04:00
const int y_axis = y_axis_in >= 0 ? y_axis_in : gp.CurrentPlot->CurrentYAxis;
return gp.MousePos[y_axis];
2020-04-28 21:17:26 -04:00
}
2020-04-27 11:27:59 -04:00
2020-05-11 07:12:22 -04:00
ImPlotLimits GetPlotLimits(int y_axis_in) {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(y_axis_in >= -1 && y_axis_in < IMPLOT_Y_AXES, "y_axis needs to between -1 and IMPLOT_Y_AXES");
2020-06-03 15:37:01 -04:00
IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "GetPlotLimits() needs to be called between BeginPlot() and EndPlot()!");
2020-05-11 07:12:22 -04:00
const int y_axis = y_axis_in >= 0 ? y_axis_in : gp.CurrentPlot->CurrentYAxis;
2020-05-12 05:19:04 -04:00
ImPlotState& plot = *gp.CurrentPlot;
2020-05-11 07:12:22 -04:00
ImPlotLimits limits;
limits.X = plot.XAxis.Range;
limits.Y = plot.YAxis[y_axis].Range;
return limits;
}
bool IsPlotQueried() {
ImPlotContext& gp = *GImPlot;
2020-06-03 15:37:01 -04:00
IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "IsPlotQueried() needs to be called between BeginPlot() and EndPlot()!");
2020-04-28 21:17:26 -04:00
return gp.CurrentPlot->Queried;
}
2020-05-11 07:12:22 -04:00
ImPlotLimits GetPlotQuery(int y_axis_in) {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(y_axis_in >= -1 && y_axis_in < IMPLOT_Y_AXES, "y_axis needs to between -1 and IMPLOT_Y_AXES");
2020-06-03 15:37:01 -04:00
IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "GetPlotQuery() needs to be called between BeginPlot() and EndPlot()!");
2020-05-12 05:19:04 -04:00
ImPlotState& plot = *gp.CurrentPlot;
2020-05-11 07:12:22 -04:00
const int y_axis = y_axis_in >= 0 ? y_axis_in : gp.CurrentPlot->CurrentYAxis;
UpdateTransformCache();
ImPlotPoint p1 = PixelsToPlot(plot.QueryRect.Min + gp.BB_Plot.Min, y_axis);
ImPlotPoint p2 = PixelsToPlot(plot.QueryRect.Max + gp.BB_Plot.Min, y_axis);
2020-05-11 07:12:22 -04:00
ImPlotLimits result;
result.X.Min = ImMin(p1.x, p2.x);
result.X.Max = ImMax(p1.x, p2.x);
result.Y.Min = ImMin(p1.y, p2.y);
result.Y.Max = ImMax(p1.y, p2.y);
return result;
}
bool IsLegendEntryHovered(const char* label_id) {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "IsPlotItemHighlight() needs to be called between BeginPlot() and EndPlot()!");
ImGuiID id = ImGui::GetID(label_id);
2020-07-26 22:28:22 -04:00
ImPlotItem* item = gp.CurrentPlot->Items.GetByKey(id);
if (item && item->Highlight)
return true;
else
return false;
}
2020-05-03 01:24:10 -04:00
//-----------------------------------------------------------------------------
2020-04-27 11:27:59 -04:00
// STYLING
2020-05-03 01:24:10 -04:00
//-----------------------------------------------------------------------------
2020-04-27 11:27:59 -04:00
2020-05-12 05:19:04 -04:00
ImPlotStyle& GetStyle() {
ImPlotContext& gp = *GImPlot;
2020-04-27 11:27:59 -04:00
return gp.Style;
}
2020-05-12 05:19:04 -04:00
void PushStyleColor(ImPlotCol idx, ImU32 col) {
ImPlotContext& gp = *GImPlot;
2020-04-27 11:27:59 -04:00
ImGuiColorMod backup;
backup.Col = idx;
backup.BackupValue = gp.Style.Colors[idx];
gp.ColorModifiers.push_back(backup);
2020-05-12 05:19:04 -04:00
gp.Style.Colors[idx] = ImGui::ColorConvertU32ToFloat4(col);
2020-04-27 11:27:59 -04:00
}
2020-05-12 05:19:04 -04:00
void PushStyleColor(ImPlotCol idx, const ImVec4& col) {
ImPlotContext& gp = *GImPlot;
2020-04-27 11:27:59 -04:00
ImGuiColorMod backup;
backup.Col = idx;
backup.BackupValue = gp.Style.Colors[idx];
gp.ColorModifiers.push_back(backup);
gp.Style.Colors[idx] = col;
}
2020-05-12 05:19:04 -04:00
void PopStyleColor(int count) {
ImPlotContext& gp = *GImPlot;
2020-04-27 11:27:59 -04:00
while (count > 0)
{
ImGuiColorMod& backup = gp.ColorModifiers.back();
gp.Style.Colors[backup.Col] = backup.BackupValue;
gp.ColorModifiers.pop_back();
count--;
}
}
2020-05-12 05:19:04 -04:00
void PushStyleVar(ImPlotStyleVar idx, float val) {
ImPlotContext& gp = *GImPlot;
2020-04-27 11:27:59 -04:00
const ImPlotStyleVarInfo* var_info = GetPlotStyleVarInfo(idx);
if (var_info->Type == ImGuiDataType_Float && var_info->Count == 1) {
float* pvar = (float*)var_info->GetVarPtr(&gp.Style);
gp.StyleModifiers.push_back(ImGuiStyleMod(idx, *pvar));
*pvar = val;
return;
}
2020-05-12 05:19:04 -04:00
IM_ASSERT(0 && "Called PushStyleVar() float variant but variable is not a float!");
2020-04-27 11:27:59 -04:00
}
2020-05-12 05:19:04 -04:00
void PushStyleVar(ImPlotStyleVar idx, int val) {
ImPlotContext& gp = *GImPlot;
2020-04-27 11:27:59 -04:00
const ImPlotStyleVarInfo* var_info = GetPlotStyleVarInfo(idx);
if (var_info->Type == ImGuiDataType_S32 && var_info->Count == 1) {
int* pvar = (int*)var_info->GetVarPtr(&gp.Style);
gp.StyleModifiers.push_back(ImGuiStyleMod(idx, *pvar));
*pvar = val;
return;
}
else if (var_info->Type == ImGuiDataType_Float && var_info->Count == 1) {
float* pvar = (float*)var_info->GetVarPtr(&gp.Style);
gp.StyleModifiers.push_back(ImGuiStyleMod(idx, *pvar));
*pvar = (float)val;
return;
}
2020-05-12 05:19:04 -04:00
IM_ASSERT(0 && "Called PushStyleVar() int variant but variable is not a int!");
2020-04-27 11:27:59 -04:00
}
void PushStyleVar(ImGuiStyleVar idx, const ImVec2& val)
{
ImPlotContext& gp = *GImPlot;
const ImPlotStyleVarInfo* var_info = GetPlotStyleVarInfo(idx);
if (var_info->Type == ImGuiDataType_Float && var_info->Count == 2)
{
ImVec2* pvar = (ImVec2*)var_info->GetVarPtr(&gp.Style);
gp.StyleModifiers.push_back(ImGuiStyleMod(idx, *pvar));
*pvar = val;
return;
}
IM_ASSERT(0 && "Called PushStyleVar() ImVec2 variant but variable is not a ImVec2!");
}
2020-05-12 05:19:04 -04:00
void PopStyleVar(int count) {
ImPlotContext& gp = *GImPlot;
2020-04-27 11:27:59 -04:00
while (count > 0) {
ImGuiStyleMod& backup = gp.StyleModifiers.back();
const ImPlotStyleVarInfo* info = GetPlotStyleVarInfo(backup.VarIdx);
void* data = info->GetVarPtr(&gp.Style);
if (info->Type == ImGuiDataType_Float && info->Count == 1) {
((float*)data)[0] = backup.BackupFloat[0];
}
else if (info->Type == ImGuiDataType_Float && info->Count == 2) {
2020-05-13 10:11:25 -04:00
((float*)data)[0] = backup.BackupFloat[0];
((float*)data)[1] = backup.BackupFloat[1];
2020-04-27 11:27:59 -04:00
}
else if (info->Type == ImGuiDataType_S32 && info->Count == 1) {
((int*)data)[0] = backup.BackupInt[0];
}
gp.StyleModifiers.pop_back();
count--;
}
}
2020-08-16 16:38:51 -04:00
//------------------------------------------------------------------------------
// COLORMAPS
//------------------------------------------------------------------------------
2020-04-27 11:27:59 -04:00
void PushColormap(ImPlotColormap colormap) {
2020-08-16 16:38:51 -04:00
ImPlotContext& gp = *GImPlot;
gp.ColormapModifiers.push_back(ImPlotColormapMod(gp.Colormap, gp.ColormapSize));
gp.Colormap = GetColormap(colormap, &gp.ColormapSize);
2020-08-16 16:38:51 -04:00
}
2020-04-27 11:27:59 -04:00
void PushColormap(const ImVec4* colormap, int size) {
2020-08-16 16:38:51 -04:00
ImPlotContext& gp = *GImPlot;
gp.ColormapModifiers.push_back(ImPlotColormapMod(gp.Colormap, gp.ColormapSize));
gp.Colormap = colormap;
gp.ColormapSize = size;
2020-08-16 16:38:51 -04:00
}
2020-04-27 11:27:59 -04:00
void PopColormap(int count) {
2020-08-16 16:38:51 -04:00
ImPlotContext& gp = *GImPlot;
while (count > 0) {
const ImPlotColormapMod& backup = gp.ColormapModifiers.back();
gp.Colormap = backup.Colormap;
gp.ColormapSize = backup.ColormapSize;
gp.ColormapModifiers.pop_back();
count--;
}
2020-08-16 16:38:51 -04:00
}
2020-04-27 11:27:59 -04:00
void SetColormap(ImPlotColormap colormap, int samples) {
2020-08-16 16:38:51 -04:00
ImPlotContext& gp = *GImPlot;
gp.Colormap = GetColormap(colormap, &gp.ColormapSize);
if (samples > 1) {
static ImVector<ImVec4> resampled;
resampled.resize(samples);
ResampleColormap(gp.Colormap, gp.ColormapSize, &resampled[0], samples);
SetColormap(&resampled[0], samples);
2020-06-02 23:07:27 -04:00
}
2020-08-24 12:48:00 -04:00
else {
BustItemCache();
}
}
2020-06-02 23:07:27 -04:00
void SetColormap(const ImVec4* colors, int size) {
ImPlotContext& gp = *GImPlot;
2020-08-24 00:45:42 -04:00
IM_ASSERT_USER_ERROR(colors != NULL, "You can't set the colors to NULL!");
IM_ASSERT_USER_ERROR(size > 0, "The number of colors must be greater than 0!");
static ImVector<ImVec4> user_colormap;
user_colormap.shrink(0);
user_colormap.reserve(size);
for (int i = 0; i < size; ++i)
user_colormap.push_back(colors[i]);
gp.Colormap = &user_colormap[0];
gp.ColormapSize = size;
2020-08-24 12:48:00 -04:00
BustItemCache();
2020-06-02 13:34:14 -04:00
}
const ImVec4* GetColormap(ImPlotColormap colormap, int* size_out) {
2020-08-24 12:06:29 -04:00
static const int csizes[ImPlotColormap_COUNT] = {10,10,9,9,12,11,11,11,11,11,11};
static const ImOffsetCalculator<ImPlotColormap_COUNT> coffs(csizes);
2020-08-24 00:45:42 -04:00
static ImVec4 cdata[] = {
2020-06-02 13:34:14 -04:00
// ImPlotColormap_Default // X11 Named Colors
ImVec4(0.0f, 0.7490196228f, 1.0f, 1.0f), // Blues::DeepSkyBlue,
ImVec4(1.0f, 0.0f, 0.0f, 1.0f), // Reds::Red,
ImVec4(0.4980392158f, 1.0f, 0.0f, 1.0f), // Greens::Chartreuse,
ImVec4(1.0f, 1.0f, 0.0f, 1.0f), // Yellows::Yellow,
ImVec4(0.0f, 1.0f, 1.0f, 1.0f), // Cyans::Cyan,
ImVec4(1.0f, 0.6470588446f, 0.0f, 1.0f), // Oranges::Orange,
ImVec4(1.0f, 0.0f, 1.0f, 1.0f), // Purples::Magenta,
ImVec4(0.5411764979f, 0.1686274558f, 0.8862745166f, 1.0f), // Purples::BlueViolet,
ImVec4(0.5f, 0.5f, 0.5f, 1.0f), // Grays::Gray50,
ImVec4(0.8235294223f, 0.7058823705f, 0.5490196347f, 1.0f), // Browns::Tan
2020-08-24 12:06:29 -04:00
// ImPlotColormap_Deep
ImVec4(0.298f, 0.447f, 0.690f, 1.000f),
ImVec4(0.867f, 0.518f, 0.322f, 1.000f),
ImVec4(0.333f, 0.659f, 0.408f, 1.000f),
ImVec4(0.769f, 0.306f, 0.322f, 1.000f),
ImVec4(0.506f, 0.446f, 0.702f, 1.000f),
ImVec4(0.576f, 0.471f, 0.376f, 1.000f),
ImVec4(0.855f, 0.545f, 0.765f, 1.000f),
ImVec4(0.549f, 0.549f, 0.549f, 1.000f),
ImVec4(0.800f, 0.725f, 0.455f, 1.000f),
ImVec4(0.392f, 0.710f, 0.804f, 1.000f),
2020-06-02 13:34:14 -04:00
// ImPlotColormap_Dark
ImVec4(0.894118f, 0.101961f, 0.109804f, 1.0f),
ImVec4(0.215686f, 0.494118f, 0.721569f, 1.0f),
ImVec4(0.301961f, 0.686275f, 0.290196f, 1.0f),
ImVec4(0.596078f, 0.305882f, 0.639216f, 1.0f),
ImVec4(1.000000f, 0.498039f, 0.000000f, 1.0f),
ImVec4(1.000000f, 1.000000f, 0.200000f, 1.0f),
ImVec4(0.650980f, 0.337255f, 0.156863f, 1.0f),
ImVec4(0.968627f, 0.505882f, 0.749020f, 1.0f),
ImVec4(0.600000f, 0.600000f, 0.600000f, 1.0f),
// ImPlotColormap_Pastel
ImVec4(0.984314f, 0.705882f, 0.682353f, 1.0f),
ImVec4(0.701961f, 0.803922f, 0.890196f, 1.0f),
ImVec4(0.800000f, 0.921569f, 0.772549f, 1.0f),
ImVec4(0.870588f, 0.796078f, 0.894118f, 1.0f),
ImVec4(0.996078f, 0.850980f, 0.650980f, 1.0f),
ImVec4(1.000000f, 1.000000f, 0.800000f, 1.0f),
ImVec4(0.898039f, 0.847059f, 0.741176f, 1.0f),
ImVec4(0.992157f, 0.854902f, 0.925490f, 1.0f),
ImVec4(0.949020f, 0.949020f, 0.949020f, 1.0f),
// ImPlotColormap_Paired
ImVec4(0.258824f, 0.807843f, 0.890196f, 1.0f),
ImVec4(0.121569f, 0.470588f, 0.705882f, 1.0f),
ImVec4(0.698039f, 0.874510f, 0.541176f, 1.0f),
ImVec4(0.200000f, 0.627451f, 0.172549f, 1.0f),
ImVec4(0.984314f, 0.603922f, 0.600000f, 1.0f),
ImVec4(0.890196f, 0.101961f, 0.109804f, 1.0f),
ImVec4(0.992157f, 0.749020f, 0.435294f, 1.0f),
ImVec4(1.000000f, 0.498039f, 0.000000f, 1.0f),
ImVec4(0.792157f, 0.698039f, 0.839216f, 1.0f),
ImVec4(0.415686f, 0.239216f, 0.603922f, 1.0f),
ImVec4(1.000000f, 1.000000f, 0.600000f, 1.0f),
ImVec4(0.694118f, 0.349020f, 0.156863f, 1.0f),
// ImPlotColormap_Viridis
ImVec4(0.267004f, 0.004874f, 0.329415f, 1.0f),
ImVec4(0.282623f, 0.140926f, 0.457517f, 1.0f),
ImVec4(0.253935f, 0.265254f, 0.529983f, 1.0f),
ImVec4(0.206756f, 0.371758f, 0.553117f, 1.0f),
ImVec4(0.163625f, 0.471133f, 0.558148f, 1.0f),
ImVec4(0.127568f, 0.566949f, 0.550556f, 1.0f),
ImVec4(0.134692f, 0.658636f, 0.517649f, 1.0f),
ImVec4(0.266941f, 0.748751f, 0.440573f, 1.0f),
ImVec4(0.477504f, 0.821444f, 0.318195f, 1.0f),
ImVec4(0.741388f, 0.873449f, 0.149561f, 1.0f),
ImVec4(0.993248f, 0.906157f, 0.143936f, 1.0f),
// ImPlotColormap_Plasma
ImVec4(5.03830e-02f, 2.98030e-02f, 5.27975e-01f, 1.00000e+00f),
ImVec4(2.54627e-01f, 1.38820e-02f, 6.15419e-01f, 1.00000e+00f),
ImVec4(4.17642e-01f, 5.64000e-04f, 6.58390e-01f, 1.00000e+00f),
ImVec4(5.62738e-01f, 5.15450e-02f, 6.41509e-01f, 1.00000e+00f),
ImVec4(6.92840e-01f, 1.65141e-01f, 5.64522e-01f, 1.00000e+00f),
ImVec4(7.98216e-01f, 2.80197e-01f, 4.69538e-01f, 1.00000e+00f),
ImVec4(8.81443e-01f, 3.92529e-01f, 3.83229e-01f, 1.00000e+00f),
ImVec4(9.49217e-01f, 5.17763e-01f, 2.95662e-01f, 1.00000e+00f),
ImVec4(9.88260e-01f, 6.52325e-01f, 2.11364e-01f, 1.00000e+00f),
ImVec4(9.88648e-01f, 8.09579e-01f, 1.45357e-01f, 1.00000e+00f),
ImVec4(9.40015e-01f, 9.75158e-01f, 1.31326e-01f, 1.00000e+00f),
// ImPlotColormap_Hot
ImVec4(0.2500f, 0.f, 0.f, 1.0f),
ImVec4(0.5000f, 0.f, 0.f, 1.0f),
ImVec4(0.7500f, 0.f, 0.f, 1.0f),
ImVec4(1.0000f, 0.f, 0.f, 1.0f),
ImVec4(1.0000f, 0.2500f, 0.f, 1.0f),
ImVec4(1.0000f, 0.5000f, 0.f, 1.0f),
ImVec4(1.0000f, 0.7500f, 0.f, 1.0f),
ImVec4(1.0000f, 1.0000f, 0.f, 1.0f),
ImVec4(1.0000f, 1.0000f, 0.3333f, 1.0f),
ImVec4(1.0000f, 1.0000f, 0.6667f, 1.0f),
ImVec4(1.0000f, 1.0000f, 1.0000f, 1.0f),
// ImPlotColormap_Cool
ImVec4( 0.f, 1.0000f, 1.0000f, 1.0f),
ImVec4(0.1000f, 0.9000f, 1.0000f, 1.0f),
ImVec4(0.2000f, 0.8000f, 1.0000f, 1.0f),
ImVec4(0.3000f, 0.7000f, 1.0000f, 1.0f),
ImVec4(0.4000f, 0.6000f, 1.0000f, 1.0f),
ImVec4(0.5000f, 0.5000f, 1.0000f, 1.0f),
ImVec4(0.6000f, 0.4000f, 1.0000f, 1.0f),
ImVec4(0.7000f, 0.3000f, 1.0000f, 1.0f),
ImVec4(0.8000f, 0.2000f, 1.0000f, 1.0f),
ImVec4(0.9000f, 0.1000f, 1.0000f, 1.0f),
ImVec4(1.0000f, 0.f, 1.0000f, 1.0f),
// ImPlotColormap_Pink
ImVec4(0.2887f, 0.f, 0.f, 1.0f),
ImVec4(0.4830f, 0.2582f, 0.2582f, 1.0f),
ImVec4(0.6191f, 0.3651f, 0.3651f, 1.0f),
ImVec4(0.7303f, 0.4472f, 0.4472f, 1.0f),
ImVec4(0.7746f, 0.5916f, 0.5164f, 1.0f),
ImVec4(0.8165f, 0.7071f, 0.5774f, 1.0f),
ImVec4(0.8563f, 0.8062f, 0.6325f, 1.0f),
ImVec4(0.8944f, 0.8944f, 0.6831f, 1.0f),
ImVec4(0.9309f, 0.9309f, 0.8028f, 1.0f),
ImVec4(0.9661f, 0.9661f, 0.9068f, 1.0f),
ImVec4(1.0000f, 1.0000f, 1.0000f, 1.0f),
// ImPlotColormap_Jet
ImVec4( 0.f, 0.f, 0.6667f, 1.0f),
ImVec4( 0.f, 0.f, 1.0000f, 1.0f),
ImVec4( 0.f, 0.3333f, 1.0000f, 1.0f),
ImVec4( 0.f, 0.6667f, 1.0000f, 1.0f),
ImVec4( 0.f, 1.0000f, 1.0000f, 1.0f),
ImVec4(0.3333f, 1.0000f, 0.6667f, 1.0f),
ImVec4(0.6667f, 1.0000f, 0.3333f, 1.0f),
ImVec4(1.0000f, 1.0000f, 0.f, 1.0f),
ImVec4(1.0000f, 0.6667f, 0.f, 1.0f),
ImVec4(1.0000f, 0.3333f, 0.f, 1.0f),
ImVec4(1.0000f, 0.f, 0.f, 1.0f)
};
*size_out = csizes[colormap];
return &cdata[coffs.Offsets[colormap]];
}
const char* GetColormapName(ImPlotColormap colormap) {
2020-08-24 12:06:29 -04:00
static const char* cmap_names[] = {"Default","Deep","Dark","Pastel","Paired","Viridis","Plasma","Hot","Cool","Pink","Jet"};
return cmap_names[colormap];
}
void ResampleColormap(const ImVec4* colormap_in, int size_in, ImVec4* colormap_out, int size_out) {
for (int i = 0; i < size_out; ++i) {
float t = i * 1.0f / (size_out - 1);
colormap_out[i] = LerpColormap(colormap_in, size_in, t);
}
2020-06-02 13:34:14 -04:00
}
int GetColormapSize() {
ImPlotContext& gp = *GImPlot;
return gp.ColormapSize;
2020-08-16 16:38:51 -04:00
}
ImVec4 GetColormapColor(int index) {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(index >= 0, "The Colormap index must be greater than zero!");
return gp.Colormap[index % gp.ColormapSize];
}
ImVec4 LerpColormap(const ImVec4* colormap, int size, float t) {
float tc = ImClamp(t,0.0f,1.0f);
int i1 = (int)((size -1 ) * tc);
int i2 = i1 + 1;
2020-08-24 00:45:42 -04:00
if (i2 == size || size == 1)
return colormap[i1];
float t1 = (float)i1 / (float)(size - 1);
float t2 = (float)i2 / (float)(size - 1);
float tr = ImRemap(t, t1, t2, 0.0f, 1.0f);
return ImLerp(colormap[i1], colormap[i2], tr);
}
ImVec4 LerpColormap(float t) {
ImPlotContext& gp = *GImPlot;
return LerpColormap(gp.Colormap, gp.ColormapSize, t);
2020-08-16 16:38:51 -04:00
}
ImVec4 NextColormapColor() {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "NextColormapColor() needs to be called between BeginPlot() and EndPlot()!");
ImVec4 col = gp.Colormap[gp.CurrentPlot->ColormapIdx % gp.ColormapSize];
gp.CurrentPlot->ColormapIdx++;
return col;
}
void ShowColormapScale(double scale_min, double scale_max, float height) {
ImPlotContext& gp = *GImPlot;
2020-08-25 22:59:43 -04:00
static ImPlotTickCollection ticks;
ticks.Reset();
ImPlotRange range;
range.Min = scale_min;
range.Max = scale_max;
2020-08-25 22:59:43 -04:00
AddTicksDefault(range, 10, 0, ticks);
2020-08-25 22:59:43 -04:00
ImGuiContext &G = *GImGui;
ImGuiWindow * Window = G.CurrentWindow;
if (Window->SkipItems)
return;
const float txt_off = 5;
const float bar_w = 20;
ImDrawList &DrawList = *Window->DrawList;
2020-08-25 22:59:43 -04:00
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))
return;
ImGui::RenderFrame(bb_frame.Min, bb_frame.Max, ImGui::GetColorU32(ImGuiCol_FrameBg));
ImRect bb_grad(bb_frame.Min + gp.Style.PlotPadding, bb_frame.Min + ImVec2(bar_w + gp.Style.PlotPadding.x, height - gp.Style.PlotPadding.y));
int num_cols = GetColormapSize();
float h_step = (height - 2 * gp.Style.PlotPadding.y) / (num_cols - 1);
for (int i = 0; i < num_cols-1; ++i) {
ImRect rect(bb_grad.Min.x, bb_grad.Min.y + h_step * i, bb_grad.Max.x, bb_grad.Min.y + h_step * (i + 1));
ImU32 col1 = ImGui::GetColorU32(GetColormapColor(num_cols - 1 - i));
ImU32 col2 = ImGui::GetColorU32(GetColormapColor(num_cols - 1 - (i+1)));
DrawList.AddRectFilledMultiColor(rect.Min, rect.Max, col1, col1, col2, col2);
}
ImU32 col_border = gp.Style.Colors[ImPlotCol_PlotBorder].w == -1 ? ImGui::GetColorU32(ImGuiCol_Text, 0.5f) : ImGui::GetColorU32(gp.Style.Colors[ImPlotCol_PlotBorder]);
ImGui::PushClipRect(bb_frame.Min, bb_frame.Max, true);
for (int i = 0; i < ticks.Size; ++i) {
2020-08-25 22:59:43 -04:00
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)
2020-08-25 22:59:43 -04:00
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();
DrawList.AddRect(bb_grad.Min, bb_grad.Max, col_border);
}
2020-08-24 00:45:42 -04:00
//-----------------------------------------------------------------------------
// Style Editor etc.
//-----------------------------------------------------------------------------
static void HelpMarker(const char* desc) {
ImGui::TextDisabled("(?)");
if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip();
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
ImGui::TextUnformatted(desc);
ImGui::PopTextWrapPos();
ImGui::EndTooltip();
}
}
2020-08-24 12:06:29 -04:00
bool ShowStyleSelector(const char* label)
{
static int style_idx = -1;
if (ImGui::Combo(label, &style_idx, "Auto\0Classic\0Dark\0Light\0"))
{
switch (style_idx)
{
case 0: StyleColorsAuto(); break;
case 1: StyleColorsClassic(); break;
case 2: StyleColorsDark(); break;
case 3: StyleColorsLight(); break;
}
return true;
}
return false;
}
2020-08-24 00:45:42 -04:00
void ShowStyleEditor(ImPlotStyle* ref) {
ImPlotContext& gp = *GImPlot;
ImPlotStyle& style = GetStyle();
static ImPlotStyle ref_saved_style;
// Default to using internal storage as reference
static bool init = true;
if (init && ref == NULL)
ref_saved_style = style;
init = false;
if (ref == NULL)
ref = &ref_saved_style;
2020-08-24 12:06:29 -04:00
if (ImPlot::ShowStyleSelector("Colors##Selector"))
ref_saved_style = style;
2020-08-24 00:45:42 -04:00
// Save/Revert button
if (ImGui::Button("Save Ref"))
*ref = ref_saved_style = style;
ImGui::SameLine();
if (ImGui::Button("Revert Ref"))
style = *ref;
ImGui::SameLine();
HelpMarker("Save/Revert in local non-persistent storage. Default Colors definition are not affected. "
"Use \"Export\" below to save them somewhere.");
if (ImGui::BeginTabBar("##StyleEditor")) {
if (ImGui::BeginTabItem("Variables")) {
ImGui::Text("Item Styling");
ImGui::SliderFloat("LineWeight", &style.LineWeight, 0.0f, 5.0f, "%.1f");
ImGui::SliderFloat("MarkerSize", &style.MarkerSize, 2.0f, 10.0f, "%.1f");
ImGui::SliderFloat("MarkerWeight", &style.MarkerWeight, 0.0f, 5.0f, "%.1f");
ImGui::SliderFloat("FillAlpha", &style.FillAlpha, 0.0f, 1.0f, "%.2f");
ImGui::SliderFloat("ErrorBarSize", &style.ErrorBarSize, 0.0f, 10.0f, "%.1f");
ImGui::SliderFloat("ErrorBarWeight", &style.ErrorBarWeight, 0.0f, 5.0f, "%.1f");
ImGui::SliderFloat("DigitalBitHeight", &style.DigitalBitHeight, 0.0f, 20.0f, "%.1f");
ImGui::SliderFloat("DigitalBitGap", &style.DigitalBitGap, 0.0f, 20.0f, "%.1f");
ImGui::Text("Plot Styling");
ImGui::SliderFloat("PlotBorderSize", &style.PlotBorderSize, 0.0f, 2.0f, "%.0f");
ImGui::SliderFloat("MinorAlpha", &style.MinorAlpha, 0.0f, 1.0f, "%.2f");
ImGui::SliderFloat2("MajorTickLen", (float*)&style.MajorTickLen, 0.0f, 20.0f, "%.0f");
ImGui::SliderFloat2("MinorTickLen", (float*)&style.MinorTickLen, 0.0f, 20.0f, "%.0f");
ImGui::SliderFloat2("MajorTickSize", (float*)&style.MajorTickSize, 0.0f, 2.0f, "%.1f");
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::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::EndTabItem();
}
if (ImGui::BeginTabItem("Colors")) {
static int output_dest = 0;
static bool output_only_modified = false;
if (ImGui::Button("Export", ImVec2(75,0))) {
if (output_dest == 0)
ImGui::LogToClipboard();
else
ImGui::LogToTTY();
ImGui::LogText("ImVec4* colors = ImPlot::GetStyle().Colors;\n");
for (int i = 0; i < ImPlotCol_COUNT; i++) {
const ImVec4& col = style.Colors[i];
const char* name = ImPlot::GetStyleColorName(i);
if (!output_only_modified || memcmp(&col, &ref->Colors[i], sizeof(ImVec4)) != 0) {
if (IsColorAuto(i))
ImGui::LogText("colors[ImPlotCol_%s]%*s= IMPLOT_COL_AUTO;\n",name,14 - (int)strlen(name), "");
else
ImGui::LogText("colors[ImPlotCol_%s]%*s= ImVec4(%.2ff, %.2ff, %.2ff, %.2ff);\n",
name, 14 - (int)strlen(name), "", col.x, col.y, col.z, col.w);
}
}
ImGui::LogFinish();
}
ImGui::SameLine(); ImGui::SetNextItemWidth(120); ImGui::Combo("##output_type", &output_dest, "To Clipboard\0To TTY\0");
ImGui::SameLine(); ImGui::Checkbox("Only Modified Colors", &output_only_modified);
static ImGuiTextFilter filter;
filter.Draw("Filter colors", ImGui::GetFontSize() * 16);
static ImGuiColorEditFlags alpha_flags = ImGuiColorEditFlags_AlphaPreviewHalf;
if (ImGui::RadioButton("Opaque", alpha_flags == ImGuiColorEditFlags_None)) { alpha_flags = ImGuiColorEditFlags_None; } ImGui::SameLine();
if (ImGui::RadioButton("Alpha", alpha_flags == ImGuiColorEditFlags_AlphaPreview)) { alpha_flags = ImGuiColorEditFlags_AlphaPreview; } ImGui::SameLine();
if (ImGui::RadioButton("Both", alpha_flags == ImGuiColorEditFlags_AlphaPreviewHalf)) { alpha_flags = ImGuiColorEditFlags_AlphaPreviewHalf; } ImGui::SameLine();
HelpMarker(
"In the color list:\n"
"Left-click on colored square to open color picker,\n"
"Right-click to open edit options menu.");
ImGui::Separator();
ImGui::PushItemWidth(-160);
for (int i = 0; i < ImPlotCol_COUNT; i++) {
const char* name = ImPlot::GetStyleColorName(i);
if (!filter.PassFilter(name))
continue;
ImGui::PushID(i);
ImVec4 temp = GetStyleColorVec4(i);
const bool is_auto = IsColorAuto(i);
if (!is_auto)
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.25f);
if (ImGui::Button("Auto")) {
if (is_auto)
style.Colors[i] = temp;
else
style.Colors[i] = IMPLOT_COL_AUTO;
BustItemCache();
}
if (!is_auto)
ImGui::PopStyleVar();
ImGui::SameLine();
if (ImGui::ColorEdit4(name, &temp.x, ImGuiColorEditFlags_NoInputs | alpha_flags)) {
style.Colors[i] = temp;
BustItemCache();
}
if (memcmp(&style.Colors[i], &ref->Colors[i], sizeof(ImVec4)) != 0) {
ImGui::SameLine(175); if (ImGui::Button("Save")) { ref->Colors[i] = style.Colors[i]; }
ImGui::SameLine(); if (ImGui::Button("Revert")) {
style.Colors[i] = ref->Colors[i];
BustItemCache();
}
}
ImGui::PopID();
}
ImGui::PopItemWidth();
ImGui::Separator();
ImGui::Text("Colors that are set to Auto (i.e. IMPLOT_COL_AUTO) will\n"
"be automatically deduced from your ImGui style or the\n"
"current ImPlot Colormap. If you want to style individual\n"
"plot items, use Push/PopStyleColor around its function.");
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("Colormaps")) {
static int output_dest = 0;
if (ImGui::Button("Export", ImVec2(75,0))) {
if (output_dest == 0)
ImGui::LogToClipboard();
else
ImGui::LogToTTY();
ImGui::LogText("static const ImVec4 colormap[%d] = {\n", gp.ColormapSize);
for (int i = 0; i < gp.ColormapSize; ++i) {
const ImVec4& col = gp.Colormap[i];
ImGui::LogText(" ImVec4(%.2ff, %.2ff, %.2ff, %.2ff)%s\n", col.x, col.y, col.z, col.w, i == gp.ColormapSize - 1 ? "" : ",");
}
ImGui::LogText("};");
ImGui::LogFinish();
}
ImGui::SameLine(); ImGui::SetNextItemWidth(120); ImGui::Combo("##output_type", &output_dest, "To Clipboard\0To TTY\0");
ImGui::SameLine(); HelpMarker("Export code for selected Colormap\n(built in or custom).");
ImGui::Separator();
static ImVector<ImVec4> custom;
static bool custom_set = false;
for (int i = 0; i < ImPlotColormap_COUNT; ++i) {
ImGui::PushID(i);
int size;
const ImVec4* cmap = GetColormap(i, &size);
bool selected = cmap == gp.Colormap;
2020-08-24 12:48:00 -04:00
if (selected) {
custom_set = false;
}
2020-08-24 00:45:42 -04:00
if (!selected)
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.25f);
if (ImGui::Button(GetColormapName(i), ImVec2(75,0))) {
SetColormap(i);
custom_set = false;
}
if (!selected)
ImGui::PopStyleVar();
ImGui::SameLine();
for (int c = 0; c < size; ++c) {
ImGui::PushID(c);
ImGui::ColorButton("",cmap[c]);
if (c != size -1)
ImGui::SameLine();
ImGui::PopID();
}
ImGui::PopID();
}
if (custom.Size == 0) {
custom.push_back(ImVec4(1,1,1,1));
custom.push_back(ImVec4(0.5f,0.5f,0.5f,1));
}
ImGui::Separator();
ImGui::BeginGroup();
bool custom_set_now = custom_set;
if (!custom_set_now)
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.25f);
if (ImGui::Button("Custom", ImVec2(75, 0))) {
SetColormap(&custom[0], custom.Size);
custom_set = true;
}
if (!custom_set_now)
ImGui::PopStyleVar();
if (ImGui::Button("+", ImVec2((75 - ImGui::GetStyle().ItemSpacing.x)/2,0))) {
custom.push_back(ImVec4(0,0,0,1));
if (custom_set) {
SetColormap(&custom[0], custom.Size);
}
}
ImGui::SameLine();
if (ImGui::Button("-", ImVec2((75 - ImGui::GetStyle().ItemSpacing.x)/2,0)) && custom.Size > 1) {
custom.pop_back();
if (custom_set) {
SetColormap(&custom[0], custom.Size);
}
}
ImGui::EndGroup();
ImGui::SameLine();
ImGui::BeginGroup();
for (int c = 0; c < custom.Size; ++c) {
ImGui::PushID(c);
if (ImGui::ColorEdit4("##Col1", &custom[c].x, ImGuiColorEditFlags_NoInputs) && custom_set) {
SetColormap(&custom[0], custom.Size);
}
if ((c + 1) % 12 != 0)
ImGui::SameLine();
ImGui::PopID();
}
ImGui::EndGroup();
ImGui::EndTabItem();
}
ImGui::EndTabBar();
}
}
void ShowUserGuide() {
ImGui::BulletText("Left click and drag within the plot area to pan X and Y axes.");
ImGui::Indent();
ImGui::BulletText("Left click and drag on an axis to pan an individual axis.");
ImGui::Unindent();
ImGui::BulletText("Scroll in the plot area to zoom both X any Y axes.");
ImGui::Indent();
ImGui::BulletText("Scroll on an axis to zoom an individual axis.");
ImGui::Unindent();
ImGui::BulletText("Right click and drag to box select data.");
ImGui::Indent();
ImGui::BulletText("Hold Alt to expand box selection horizontally.");
ImGui::BulletText("Hold Shift to expand box selection vertically.");
ImGui::BulletText("Left click while box selecting to cancel the selection.");
ImGui::Unindent();
ImGui::BulletText("Double left click to fit all visible data.");
ImGui::Indent();
ImGui::BulletText("Double left click on an axis to fit the individual axis.");
ImGui::Unindent();
ImGui::BulletText("Double right click to open the full plot context menu.");
ImGui::Indent();
ImGui::BulletText("Double right click on an axis to open the axis context menu.");
ImGui::Unindent();
ImGui::BulletText("Click legend label icons to show/hide plot items.");
}
2020-08-24 12:06:29 -04:00
void StyleColorsAuto(ImPlotStyle* dst) {
ImPlotStyle* style = dst ? dst : &ImPlot::GetStyle();
ImVec4* colors = style->Colors;
2020-08-24 12:06:43 -04:00
style->MinorAlpha = 0.25f;
2020-08-24 12:06:29 -04:00
colors[ImPlotCol_Line] = IMPLOT_COL_AUTO;
colors[ImPlotCol_Fill] = IMPLOT_COL_AUTO;
colors[ImPlotCol_MarkerOutline] = IMPLOT_COL_AUTO;
colors[ImPlotCol_MarkerFill] = IMPLOT_COL_AUTO;
colors[ImPlotCol_ErrorBar] = IMPLOT_COL_AUTO;
colors[ImPlotCol_FrameBg] = IMPLOT_COL_AUTO;
colors[ImPlotCol_PlotBg] = IMPLOT_COL_AUTO;
colors[ImPlotCol_PlotBorder] = IMPLOT_COL_AUTO;
colors[ImPlotCol_LegendBg] = IMPLOT_COL_AUTO;
colors[ImPlotCol_LegendBorder] = IMPLOT_COL_AUTO;
colors[ImPlotCol_LegendText] = IMPLOT_COL_AUTO;
colors[ImPlotCol_TitleText] = IMPLOT_COL_AUTO;
colors[ImPlotCol_InlayText] = IMPLOT_COL_AUTO;
colors[ImPlotCol_PlotBorder] = IMPLOT_COL_AUTO;
colors[ImPlotCol_XAxis] = IMPLOT_COL_AUTO;
colors[ImPlotCol_XAxisGrid] = IMPLOT_COL_AUTO;
colors[ImPlotCol_YAxis] = IMPLOT_COL_AUTO;
colors[ImPlotCol_YAxisGrid] = IMPLOT_COL_AUTO;
colors[ImPlotCol_YAxis2] = IMPLOT_COL_AUTO;
colors[ImPlotCol_YAxisGrid2] = IMPLOT_COL_AUTO;
colors[ImPlotCol_YAxis3] = IMPLOT_COL_AUTO;
colors[ImPlotCol_YAxisGrid3] = IMPLOT_COL_AUTO;
colors[ImPlotCol_Selection] = IMPLOT_COL_AUTO;
colors[ImPlotCol_Query] = IMPLOT_COL_AUTO;
colors[ImPlotCol_Crosshairs] = IMPLOT_COL_AUTO;
}
void StyleColorsClassic(ImPlotStyle* dst) {
ImPlotStyle* style = dst ? dst : &ImPlot::GetStyle();
ImVec4* colors = style->Colors;
2020-08-24 12:06:43 -04:00
style->MinorAlpha = 0.5f;
2020-08-24 12:06:29 -04:00
colors[ImPlotCol_Line] = IMPLOT_COL_AUTO;
colors[ImPlotCol_Fill] = IMPLOT_COL_AUTO;
colors[ImPlotCol_MarkerOutline] = IMPLOT_COL_AUTO;
colors[ImPlotCol_MarkerFill] = IMPLOT_COL_AUTO;
colors[ImPlotCol_ErrorBar] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f);
colors[ImPlotCol_FrameBg] = ImVec4(0.43f, 0.43f, 0.43f, 0.39f);
colors[ImPlotCol_PlotBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.35f);
colors[ImPlotCol_PlotBorder] = ImVec4(0.50f, 0.50f, 0.50f, 0.50f);
colors[ImPlotCol_LegendBg] = ImVec4(0.11f, 0.11f, 0.14f, 0.92f);
colors[ImPlotCol_LegendBorder] = ImVec4(0.50f, 0.50f, 0.50f, 0.50f);
colors[ImPlotCol_LegendText] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f);
colors[ImPlotCol_TitleText] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f);
colors[ImPlotCol_InlayText] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f);
colors[ImPlotCol_XAxis] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f);
colors[ImPlotCol_XAxisGrid] = ImVec4(0.90f, 0.90f, 0.90f, 0.25f);
colors[ImPlotCol_YAxis] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f);
colors[ImPlotCol_YAxisGrid] = ImVec4(0.90f, 0.90f, 0.90f, 0.25f);
colors[ImPlotCol_YAxis2] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f);
colors[ImPlotCol_YAxisGrid2] = ImVec4(0.90f, 0.90f, 0.90f, 0.25f);
colors[ImPlotCol_YAxis3] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f);
colors[ImPlotCol_YAxisGrid3] = ImVec4(0.90f, 0.90f, 0.90f, 0.25f);
colors[ImPlotCol_Selection] = ImVec4(0.97f, 0.97f, 0.39f, 1.00f);
colors[ImPlotCol_Query] = ImVec4(0.00f, 1.00f, 0.59f, 1.00f);
colors[ImPlotCol_Crosshairs] = ImVec4(0.50f, 0.50f, 0.50f, 0.75f);
}
void StyleColorsDark(ImPlotStyle* dst) {
ImPlotStyle* style = dst ? dst : &ImPlot::GetStyle();
ImVec4* colors = style->Colors;
2020-08-24 12:06:43 -04:00
style->MinorAlpha = 0.25f;
2020-08-24 12:06:29 -04:00
colors[ImPlotCol_Line] = IMPLOT_COL_AUTO;
colors[ImPlotCol_Fill] = IMPLOT_COL_AUTO;
colors[ImPlotCol_MarkerOutline] = IMPLOT_COL_AUTO;
colors[ImPlotCol_MarkerFill] = IMPLOT_COL_AUTO;
colors[ImPlotCol_ErrorBar] = IMPLOT_COL_AUTO;
colors[ImPlotCol_FrameBg] = ImVec4(1.00f, 1.00f, 1.00f, 0.07f);
colors[ImPlotCol_PlotBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.50f);
colors[ImPlotCol_PlotBorder] = ImVec4(0.43f, 0.43f, 0.50f, 0.50f);
colors[ImPlotCol_LegendBg] = ImVec4(0.08f, 0.08f, 0.08f, 0.94f);
colors[ImPlotCol_LegendBorder] = ImVec4(0.43f, 0.43f, 0.50f, 0.50f);
colors[ImPlotCol_LegendText] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
colors[ImPlotCol_TitleText] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
colors[ImPlotCol_InlayText] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
colors[ImPlotCol_XAxis] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
colors[ImPlotCol_XAxisGrid] = ImVec4(1.00f, 1.00f, 1.00f, 0.25f);
colors[ImPlotCol_YAxis] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
colors[ImPlotCol_YAxisGrid] = ImVec4(1.00f, 1.00f, 1.00f, 0.25f);
colors[ImPlotCol_YAxis2] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
colors[ImPlotCol_YAxisGrid2] = ImVec4(1.00f, 1.00f, 1.00f, 0.25f);
colors[ImPlotCol_YAxis3] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
colors[ImPlotCol_YAxisGrid3] = ImVec4(1.00f, 1.00f, 1.00f, 0.25f);
colors[ImPlotCol_Selection] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f);
colors[ImPlotCol_Query] = ImVec4(0.00f, 1.00f, 0.44f, 1.00f);
colors[ImPlotCol_Crosshairs] = ImVec4(1.00f, 1.00f, 1.00f, 0.50f);
}
void StyleColorsLight(ImPlotStyle* dst) {
ImPlotStyle* style = dst ? dst : &ImPlot::GetStyle();
ImVec4* colors = style->Colors;
2020-08-24 12:06:43 -04:00
style->MinorAlpha = 1.0f;
2020-08-24 12:06:29 -04:00
colors[ImPlotCol_Line] = IMPLOT_COL_AUTO;
colors[ImPlotCol_Fill] = IMPLOT_COL_AUTO;
colors[ImPlotCol_MarkerOutline] = IMPLOT_COL_AUTO;
colors[ImPlotCol_MarkerFill] = IMPLOT_COL_AUTO;
colors[ImPlotCol_ErrorBar] = IMPLOT_COL_AUTO;
colors[ImPlotCol_FrameBg] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
colors[ImPlotCol_PlotBg] = ImVec4(0.42f, 0.57f, 1.00f, 0.13f);
colors[ImPlotCol_PlotBorder] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
colors[ImPlotCol_LegendBg] = ImVec4(1.00f, 1.00f, 1.00f, 0.98f);
colors[ImPlotCol_LegendBorder] = ImVec4(0.82f, 0.82f, 0.82f, 0.80f);
colors[ImPlotCol_LegendText] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f);
colors[ImPlotCol_TitleText] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f);
colors[ImPlotCol_InlayText] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f);
colors[ImPlotCol_XAxis] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f);
colors[ImPlotCol_XAxisGrid] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
colors[ImPlotCol_YAxis] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f);
colors[ImPlotCol_YAxisGrid] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
colors[ImPlotCol_YAxis2] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f);
colors[ImPlotCol_YAxisGrid2] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
colors[ImPlotCol_YAxis3] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f);
colors[ImPlotCol_YAxisGrid3] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
colors[ImPlotCol_Selection] = ImVec4(0.82f, 0.64f, 0.03f, 1.00f);
colors[ImPlotCol_Query] = ImVec4(0.00f, 0.84f, 0.37f, 1.00f);
colors[ImPlotCol_Crosshairs] = ImVec4(0.00f, 0.00f, 0.00f, 0.50f);
}
2020-08-24 00:45:42 -04:00
} // namespace ImPlot