aboutsummaryrefslogtreecommitdiff
path: root/3rdparty/implot
diff options
context:
space:
mode:
authorrtk0c <[email protected]>2022-02-19 13:30:03 -0800
committerrtk0c <[email protected]>2022-02-19 13:30:03 -0800
commit9dcdcf68f6a60741cbdd287e7eda23b4a21a080e (patch)
treef5ff4c569607e1f63de9dd87bb7442e021b1f620 /3rdparty/implot
parent2599909052ef552efd5622bf73b60913e815b498 (diff)
Fix build errors and update all dependencies to latest version
- Fixed doctest executable not compiling - Fixed class accessibility error in Workflow_Main.cpp - Fixed selection of OpenGL loader in imgui OpenGL 2 & 3 backends - All loading is handled in our code now, the imgui_*_backend.cpp files are instructed to do nothing
Diffstat (limited to '3rdparty/implot')
-rw-r--r--3rdparty/implot/epezent-implot.stamp2
-rw-r--r--3rdparty/implot/implot.cpp4591
-rw-r--r--3rdparty/implot/implot.h783
-rw-r--r--3rdparty/implot/implot_demo.cpp3021
-rw-r--r--3rdparty/implot/implot_internal.h879
-rw-r--r--3rdparty/implot/implot_items.cpp952
6 files changed, 6311 insertions, 3917 deletions
diff --git a/3rdparty/implot/epezent-implot.stamp b/3rdparty/implot/epezent-implot.stamp
index 7279f6c..8c13dd4 100644
--- a/3rdparty/implot/epezent-implot.stamp
+++ b/3rdparty/implot/epezent-implot.stamp
@@ -1,2 +1,2 @@
# This file labels the commit which our source is from
-555ff688a8134bc0c602123149abe9c17d577475 \ No newline at end of file
+b47c8bacdbc78bc521691f70666f13924bb522ab \ No newline at end of file
diff --git a/3rdparty/implot/implot.cpp b/3rdparty/implot/implot.cpp
index f97e08c..3747627 100644
--- a/3rdparty/implot/implot.cpp
+++ b/3rdparty/implot/implot.cpp
@@ -20,7 +20,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
-// ImPlot v0.10 WIP
+// ImPlot v0.13 WIP
/*
@@ -31,78 +31,116 @@ Below is a change-log of API breaking changes only. If you are using one of the
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.
-- 2021/03/08 (0.9) - SetColormap and PushColormap(ImVec4*) were removed. Use AddColormap for custom colormap support. LerpColormap was changed to SampleColormap.
- ShowColormapScale was changed to ColormapScale and requires additional arguments.
-- 2021/03/07 (0.9) - The signature of ShowColormapScale was modified to accept a ImVec2 size.
-- 2021/02/28 (0.9) - BeginLegendDragDropSource was changed to BeginDragDropSourceItem with a number of other drag and drop improvements.
-- 2021/01/18 (0.9) - The default behavior for opening context menus was change from double right-click to single right-click. ImPlotInputMap and related functions were moved
- to implot_internal.h due to its immaturity.
-- 2020/10/16 (0.8) - ImPlotStyleVar_InfoPadding was changed to ImPlotStyleVar_MousePosPadding
-- 2020/09/10 (0.8) - The single array versions of PlotLine, PlotScatter, PlotStems, and PlotShaded were given additional arguments for x-scale and x0.
-- 2020/09/07 (0.8) - Plotting functions which accept a custom getter function pointer have been post-fixed with a G (e.g. PlotLineG)
-- 2020/09/06 (0.7) - Several flags under ImPlotFlags and ImPlotAxisFlags were inverted (e.g. ImPlotFlags_Legend -> ImPlotFlags_NoLegend) so that the default flagset
- is simply 0. This more closely matches ImGui's style and makes it easier to enable non-default but commonly used flags (e.g. ImPlotAxisFlags_Time).
-- 2020/08/28 (0.5) - ImPlotMarker_ can no longer be combined with bitwise OR, |. This features caused unecessary slow-down, and almost no one used it.
-- 2020/08/25 (0.5) - ImPlotAxisFlags_Scientific was removed. Logarithmic axes automatically uses scientific notation.
-- 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/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 (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`
- 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/11 (0.2) - The namespace ImGui:: was replaced with ImPlot::. As a result, the following additional changes were made:
- - Functions that were prefixed or decorated with the word "Plot" have been truncated. E.g., `ImGui::PlotBars` is now just `ImPlot::Bar`.
- It should be fairly obvious what was what.
- - 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/10 (0.2) - The following function/struct names were changes:
- - ImPlotRange -> ImPlotLimits
- - GetPlotRange() -> GetPlotLimits()
- - SetNextPlotRange -> SetNextPlotLimits
- - 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.
+- 2021/10/19 (0.13) MAJOR API OVERHAUL!
+ - TRIVIAL RENAME:
+ - ImPlotLimits -> ImPlotRect
+ - ImPlotYAxis_ -> ImAxis_
+ - SetPlotYAxis -> SetAxis
+ - BeginDragDropTarget -> BeginDragDropTargetPlot
+ - BeginDragDropSource -> BeginDragDropSourcePlot
+ - ImPlotFlags_NoMousePos -> ImPlotFlags_NoMouseText
+ - SetNextPlotLimits -> SetNextAxesLimits
+ - SetMouseTextLocation -> SetupMouseText
+ - SIGNATURE MODIFIED:
+ - PixelsToPlot/PlotToPixels -> added optional X-Axis arg
+ - GetPlotMousePos -> added optional X-Axis arg
+ - GetPlotLimits -> added optional X-Axis arg
+ - GetPlotSelection -> added optional X-Axis arg
+ - DragLineX/Y/DragPoint -> now takes int id; removed labels (render with Annotation/Tag instead)
+ - REPLACED:
+ - IsPlotXAxisHovered/IsPlotXYAxisHovered -> IsAxisHovered(ImAxis)
+ - BeginDragDropTargetX/BeginDragDropTargetY -> BeginDragDropTargetAxis(ImAxis)
+ - BeginDragDropSourceX/BeginDragDropSourceY -> BeginDragDropSourceAxis(ImAxis)
+ - ImPlotCol_XAxis, ImPlotCol_YAxis1, etc. -> ImPlotCol_AxisText (push/pop this around SetupAxis to style individual axes)
+ - ImPlotCol_XAxisGrid, ImPlotCol_Y1AxisGrid -> ImPlotCol_AxisGrid (push/pop this around SetupAxis to style individual axes)
+ - SetNextPlotLimitsX/Y -> SetNextAxisLimits(ImAxis)
+ - LinkNextPlotLimits -> SetNextAxisLinks(ImAxis)
+ - FitNextPlotAxes -> SetNextAxisToFit(ImAxis)/SetNextAxesToFit
+ - SetLegendLocation -> SetupLegend
+ - ImPlotFlags_NoHighlight -> ImPlotLegendFlags_NoHighlight
+ - ImPlotOrientation -> ImPlotLegendFlags_Horizontal
+ - Annotate -> Annotation
+ - REMOVED:
+ - GetPlotQuery, SetPlotQuery, IsPlotQueried -> use DragRect
+ - SetNextPlotTicksX, SetNextPlotTicksY -> use SetupAxisTicks
+ - SetNextPlotFormatX, SetNextPlotFormatY -> use SetupAxisFormat
+ - AnnotateClamped -> use Annotation(bool clamp = true)
+ - OBSOLETED:
+ - BeginPlot (original signature) -> use simplified signature + Setup API
+- 2021/07/30 (0.12) - The offset argument of `PlotXG` functions was been removed. Implement offsetting in your getter callback instead.
+- 2021/03/08 (0.9) - SetColormap and PushColormap(ImVec4*) were removed. Use AddColormap for custom colormap support. LerpColormap was changed to SampleColormap.
+ ShowColormapScale was changed to ColormapScale and requires additional arguments.
+- 2021/03/07 (0.9) - The signature of ShowColormapScale was modified to accept a ImVec2 size.
+- 2021/02/28 (0.9) - BeginLegendDragDropSource was changed to BeginDragDropSourceItem with a number of other drag and drop improvements.
+- 2021/01/18 (0.9) - The default behavior for opening context menus was change from double right-click to single right-click. ImPlotInputMap and related functions were moved
+ to implot_internal.h due to its immaturity.
+- 2020/10/16 (0.8) - ImPlotStyleVar_InfoPadding was changed to ImPlotStyleVar_MousePosPadding
+- 2020/09/10 (0.8) - The single array versions of PlotLine, PlotScatter, PlotStems, and PlotShaded were given additional arguments for x-scale and x0.
+- 2020/09/07 (0.8) - Plotting functions which accept a custom getter function pointer have been post-fixed with a G (e.g. PlotLineG)
+- 2020/09/06 (0.7) - Several flags under ImPlotFlags and ImPlotAxisFlags were inverted (e.g. ImPlotFlags_Legend -> ImPlotFlags_NoLegend) so that the default flagset
+ is simply 0. This more closely matches ImGui's style and makes it easier to enable non-default but commonly used flags (e.g. ImPlotAxisFlags_Time).
+- 2020/08/28 (0.5) - ImPlotMarker_ can no longer be combined with bitwise OR, |. This features caused unecessary slow-down, and almost no one used it.
+- 2020/08/25 (0.5) - ImPlotAxisFlags_Scientific was removed. Logarithmic axes automatically uses scientific notation.
+- 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/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 (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`
+ 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/11 (0.2) - The namespace ImGui:: was replaced with ImPlot::. As a result, the following additional changes were made:
+ - Functions that were prefixed or decorated with the word "Plot" have been truncated. E.g., `ImGui::PlotBars` is now just `ImPlot::Bar`.
+ It should be fairly obvious what was what.
+ - 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/10 (0.2) - The following function/struct names were changes:
+ - ImPlotRange -> ImPlotLimits
+ - GetPlotRange() -> GetPlotLimits()
+ - SetNextPlotRange -> SetNextPlotLimits
+ - 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"
#include "implot_internal.h"
-#ifdef _MSC_VER
-#define sprintf sprintf_s
-#endif
+#include <stdlib.h>
-// Support for pre-1.82 version. Users on 1.82+ can use 0 (default) flags to mean "all corners" but in order to support older versions we are more explicit.
+// Support for pre-1.82 versions. Users on 1.82+ can use 0 (default) flags to mean "all corners" but in order to support older versions we are more explicit.
#if (IMGUI_VERSION_NUM < 18102) && !defined(ImDrawFlags_RoundCornersAll)
#define ImDrawFlags_RoundCornersAll ImDrawCornerFlags_All
#endif
+// Visual Studio warnings
+#ifdef _MSC_VER
+#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
+#endif
+
+// Clang/GCC warnings with -Weverything
+#if defined(__clang__)
+#pragma clang diagnostic ignored "-Wformat-nonliteral" // warning: format string is not a string literal
+#elif defined(__GNUC__)
+#pragma GCC diagnostic ignored "-Wformat-nonliteral" // warning: format not a string literal, format string not checked
+#endif
+
// Global plot context
+#ifndef GImPlot
ImPlotContext* GImPlot = NULL;
+#endif
//-----------------------------------------------------------------------------
// Struct Implementations
//-----------------------------------------------------------------------------
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;
+ ImPlot::MapInputDefault(this);
}
ImPlotStyle::ImPlotStyle() {
@@ -134,7 +172,7 @@ ImPlotStyle::ImPlotStyle() {
AnnotationPadding = ImVec2(2,2);
FitPadding = ImVec2(0,0);
PlotDefaultSize = ImVec2(400,300);
- PlotMinSize = ImVec2(300,225);
+ PlotMinSize = ImVec2(200,150);
ImPlot::StyleColorsAuto(this);
@@ -146,18 +184,6 @@ ImPlotStyle::ImPlotStyle() {
UseISO8601 = false;
}
-ImPlotItem* ImPlotPlot::GetLegendItem(int i) {
- IM_ASSERT(Items.GetSize() > 0);
- return Items.GetByIndex(LegendData.Indices[i]);
-}
-
-const char* ImPlotPlot::GetLegendLabel(int i) {
- ImPlotItem* item = GetLegendItem(i);
- IM_ASSERT(item != NULL);
- IM_ASSERT(item->NameOffset != -1 && item->NameOffset < LegendData.Labels.Buf.Size);
- return LegendData.Labels.Buf.Data + item->NameOffset;
-}
-
//-----------------------------------------------------------------------------
// Style
//-----------------------------------------------------------------------------
@@ -165,7 +191,7 @@ const char* ImPlotPlot::GetLegendLabel(int i) {
namespace ImPlot {
const char* GetStyleColorName(ImPlotCol col) {
- static const char* col_names[] = {
+ static const char* col_names[ImPlotCol_COUNT] = {
"Line",
"Fill",
"MarkerOutline",
@@ -179,16 +205,13 @@ const char* GetStyleColorName(ImPlotCol col) {
"LegendText",
"TitleText",
"InlayText",
- "XAxis",
- "XAxisGrid",
- "YAxis",
- "YAxisGrid",
- "YAxis2",
- "YAxisGrid2",
- "YAxis3",
- "YAxisGrid3",
+ "AxisText",
+ "AxisGrid",
+ "AxisTick",
+ "AxisBg",
+ "AxisBgHovered",
+ "AxisBgActive",
"Selection",
- "Query",
"Crosshairs"
};
return col_names[col];
@@ -227,16 +250,13 @@ ImVec4 GetAutoColor(ImPlotCol idx) {
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_AxisText: return ImGui::GetStyleColorVec4(ImGuiCol_Text);
+ case ImPlotCol_AxisGrid: return GetStyleColorVec4(ImPlotCol_AxisText) * ImVec4(1,1,1,0.25f);
+ case ImPlotCol_AxisTick: return GetStyleColorVec4(ImPlotCol_AxisGrid);
+ case ImPlotCol_AxisBg: return ImVec4(0,0,0,0);
+ case ImPlotCol_AxisBgHovered: return ImGui::GetStyleColorVec4(ImGuiCol_ButtonHovered);
+ case ImPlotCol_AxisBgActive: return ImGui::GetStyleColorVec4(ImGuiCol_ButtonActive);
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;
}
@@ -335,11 +355,26 @@ void AddTextVertical(ImDrawList *DrawList, ImVec2 pos, ImU32 col, const char *te
DrawList->PrimUnreserve(chars_skp*6, chars_skp*4);
}
+void AddTextCentered(ImDrawList* DrawList, ImVec2 top_center, ImU32 col, const char* text_begin, const char* text_end) {
+ float txt_ht = ImGui::GetTextLineHeight();
+ const char* title_end = ImGui::FindRenderedTextEnd(text_begin, text_end);
+ ImVec2 text_size;
+ float y = 0;
+ while (const char* tmp = (const char*)memchr(text_begin, '\n', title_end-text_begin)) {
+ text_size = ImGui::CalcTextSize(text_begin,tmp,true);
+ DrawList->AddText(ImVec2(top_center.x - text_size.x * 0.5f, top_center.y+y),col,text_begin,tmp);
+ text_begin = tmp + 1;
+ y += txt_ht;
+ }
+ text_size = ImGui::CalcTextSize(text_begin,title_end,true);
+ DrawList->AddText(ImVec2(top_center.x - text_size.x * 0.5f, top_center.y+y),col,text_begin,title_end);
+}
+
double NiceNum(double x, bool round) {
- double f; /* fractional part of x */
- double nf; /* nice, rounded fraction */
+ double f;
+ double nf;
int expv = (int)floor(ImLog10(x));
- f = x / ImPow(10.0, (double)expv); /* between 1 and 10 */
+ f = x / ImPow(10.0, (double)expv);
if (round)
if (f < 1.5)
nf = 1;
@@ -396,7 +431,9 @@ void SetCurrentContext(ImPlotContext* ctx) {
#define IM_RGB(r,g,b) IM_COL32(r,g,b,255)
void Initialize(ImPlotContext* ctx) {
- Reset(ctx);
+ ResetCtxForNextPlot(ctx);
+ ResetCtxForNextAlignedPlots(ctx);
+ ResetCtxForNextSubplot(ctx);
const ImU32 Deep[] = {4289753676, 4283598045, 4285048917, 4283584196, 4289950337, 4284512403, 4291005402, 4287401100, 4285839820, 4291671396 };
const ImU32 Dark[] = {4280031972, 4290281015, 4283084621, 4288892568, 4278222847, 4281597951, 4280833702, 4290740727, 4288256409 };
@@ -431,10 +468,9 @@ void Initialize(ImPlotContext* ctx) {
IMPLOT_APPEND_CMAP(PiYG, false);
IMPLOT_APPEND_CMAP(Spectral, false);
IMPLOT_APPEND_CMAP(Greys, false);
-
}
-void Reset(ImPlotContext* ctx) {
+void ResetCtxForNextPlot(ImPlotContext* ctx) {
// end child window if it was made
if (ctx->ChildWindowMade)
ImGui::EndChild();
@@ -442,24 +478,11 @@ void Reset(ImPlotContext* ctx) {
// reset the next plot/item data
ctx->NextPlotData.Reset();
ctx->NextItemData.Reset();
- // reset items count
- ctx->VisibleItemCount = 0;
- // reset ticks/labels
- ctx->XTicks.Reset();
- for (int i = 0; i < 3; ++i)
- ctx->YTicks[i].Reset();
// reset labels
ctx->Annotations.Reset();
+ ctx->Tags.Reset();
// reset extents/fit
- ctx->FitThisFrame = false;
- ctx->FitX = false;
- ctx->ExtentsX.Min = HUGE_VAL;
- ctx->ExtentsX.Max = -HUGE_VAL;
- for (int i = 0; i < IMPLOT_Y_AXES; i++) {
- ctx->ExtentsY[i].Min = HUGE_VAL;
- ctx->ExtentsY[i].Max = -HUGE_VAL;
- ctx->FitY[i] = false;
- }
+ ctx->OpenContextThisFrame = false;
// reset digital plot items count
ctx->DigitalPlotItemCnt = 0;
ctx->DigitalPlotOffset = 0;
@@ -469,6 +492,17 @@ void Reset(ImPlotContext* ctx) {
ctx->PreviousItem = NULL;
}
+void ResetCtxForNextAlignedPlots(ImPlotContext* ctx) {
+ ctx->CurrentAlignmentH = NULL;
+ ctx->CurrentAlignmentV = NULL;
+}
+
+void ResetCtxForNextSubplot(ImPlotContext* ctx) {
+ ctx->CurrentSubplot = NULL;
+ ctx->CurrentAlignmentH = NULL;
+ ctx->CurrentAlignmentV = NULL;
+}
+
//-----------------------------------------------------------------------------
// Plot Utils
//-----------------------------------------------------------------------------
@@ -485,82 +519,7 @@ ImPlotPlot* GetCurrentPlot() {
void BustPlotCache() {
GImPlot->Plots.Clear();
-}
-
-void PushLinkedAxis(ImPlotAxis& axis) {
- if (axis.LinkedMin) { *axis.LinkedMin = axis.Range.Min; }
- if (axis.LinkedMax) { *axis.LinkedMax = axis.Range.Max; }
-}
-
-void PullLinkedAxis(ImPlotAxis& axis) {
- if (axis.LinkedMin) { axis.SetMin(*axis.LinkedMin,true); }
- if (axis.LinkedMax) { axis.SetMax(*axis.LinkedMax,true); }
-}
-
-//-----------------------------------------------------------------------------
-// Coordinate Utils
-//-----------------------------------------------------------------------------
-
-void UpdateTransformCache() {
- ImPlotContext& gp = *GImPlot;
- // get pixels for transforms
- for (int i = 0; i < IMPLOT_Y_AXES; i++) {
- gp.PixelRange[i] = ImRect(ImHasFlag(gp.CurrentPlot->XAxis.Flags, ImPlotAxisFlags_Invert) ? gp.CurrentPlot->PlotRect.Max.x : gp.CurrentPlot->PlotRect.Min.x,
- ImHasFlag(gp.CurrentPlot->YAxis[i].Flags, ImPlotAxisFlags_Invert) ? gp.CurrentPlot->PlotRect.Min.y : gp.CurrentPlot->PlotRect.Max.y,
- ImHasFlag(gp.CurrentPlot->XAxis.Flags, ImPlotAxisFlags_Invert) ? gp.CurrentPlot->PlotRect.Min.x : gp.CurrentPlot->PlotRect.Max.x,
- ImHasFlag(gp.CurrentPlot->YAxis[i].Flags, ImPlotAxisFlags_Invert) ? gp.CurrentPlot->PlotRect.Max.y : gp.CurrentPlot->PlotRect.Min.y);
- gp.My[i] = (gp.PixelRange[i].Max.y - gp.PixelRange[i].Min.y) / gp.CurrentPlot->YAxis[i].Range.Size();
- }
- gp.LogDenX = ImLog10(gp.CurrentPlot->XAxis.Range.Max / gp.CurrentPlot->XAxis.Range.Min);
- for (int i = 0; i < IMPLOT_Y_AXES; i++)
- gp.LogDenY[i] = ImLog10(gp.CurrentPlot->YAxis[i].Range.Max / gp.CurrentPlot->YAxis[i].Range.Min);
- gp.Mx = (gp.PixelRange[0].Max.x - gp.PixelRange[0].Min.x) / gp.CurrentPlot->XAxis.Range.Size();
-}
-
-ImPlotPoint PixelsToPlot(float x, float y, ImPlotYAxis y_axis_in) {
- ImPlotContext& gp = *GImPlot;
- IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "PixelsToPlot() needs to be called between BeginPlot() and EndPlot()!");
- const ImPlotYAxis y_axis = y_axis_in >= 0 ? y_axis_in : gp.CurrentPlot->CurrentYAxis;
- ImPlotPoint plt;
- 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;
- if (ImHasFlag(gp.CurrentPlot->XAxis.Flags, ImPlotAxisFlags_LogScale)) {
- 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;
- }
- if (ImHasFlag(gp.CurrentPlot->YAxis[y_axis].Flags, ImPlotAxisFlags_LogScale)) {
- 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;
- }
- return plt;
-}
-
-ImPlotPoint PixelsToPlot(const ImVec2& pix, ImPlotYAxis y_axis) {
- 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.
-ImVec2 PlotToPixels(double x, double y, ImPlotYAxis y_axis_in) {
- ImPlotContext& gp = *GImPlot;
- IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "PlotToPixels() needs to be called between BeginPlot() and EndPlot()!");
- const ImPlotYAxis y_axis = y_axis_in >= 0 ? y_axis_in : gp.CurrentPlot->CurrentYAxis;
- ImVec2 pix;
- if (ImHasFlag(gp.CurrentPlot->XAxis.Flags, ImPlotAxisFlags_LogScale)) {
- double t = ImLog10(x / gp.CurrentPlot->XAxis.Range.Min) / gp.LogDenX;
- x = ImLerp(gp.CurrentPlot->XAxis.Range.Min, gp.CurrentPlot->XAxis.Range.Max, (float)t);
- }
- if (ImHasFlag(gp.CurrentPlot->YAxis[y_axis].Flags, ImPlotAxisFlags_LogScale)) {
- double t = ImLog10(y / gp.CurrentPlot->YAxis[y_axis].Range.Min) / gp.LogDenY[y_axis];
- y = ImLerp(gp.CurrentPlot->YAxis[y_axis].Range.Min, gp.CurrentPlot->YAxis[y_axis].Range.Max, (float)t);
- }
- 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));
- return pix;
-}
-
-// This function is convenient but should not be used to process a high volume of points. Use the Transformer structs below instead.
-ImVec2 PlotToPixels(const ImPlotPoint& plt, ImPlotYAxis y_axis) {
- return PlotToPixels(plt.x, plt.y, y_axis);
+ GImPlot->Subplots.Clear();
}
//-----------------------------------------------------------------------------
@@ -587,29 +546,37 @@ ImVec2 GetLocationPos(const ImRect& outer_rect, const ImVec2& inner_size, ImPlot
return pos;
}
-ImVec2 CalcLegendSize(ImPlotPlot& plot, const ImVec2& pad, const ImVec2& spacing, ImPlotOrientation orn) {
+ImVec2 CalcLegendSize(ImPlotItemGroup& items, const ImVec2& pad, const ImVec2& spacing, bool vertical) {
// vars
- const int nItems = plot.GetLegendCount();
+ const int nItems = items.GetLegendCount();
const float txt_ht = ImGui::GetTextLineHeight();
const float icon_size = txt_ht;
// get label max width
float max_label_width = 0;
float sum_label_width = 0;
for (int i = 0; i < nItems; ++i) {
- const char* label = plot.GetLegendLabel(i);
+ const char* label = items.GetLegendLabel(i);
const float label_width = ImGui::CalcTextSize(label, NULL, true).x;
max_label_width = label_width > max_label_width ? label_width : max_label_width;
sum_label_width += label_width;
}
// calc legend size
- const ImVec2 legend_size = orn == ImPlotOrientation_Vertical ?
+ const ImVec2 legend_size = vertical ?
ImVec2(pad.x * 2 + icon_size + max_label_width, pad.y * 2 + nItems * txt_ht + (nItems - 1) * spacing.y) :
ImVec2(pad.x * 2 + icon_size * nItems + sum_label_width + (nItems - 1) * spacing.x, pad.y * 2 + txt_ht);
return legend_size;
}
-void ShowLegendEntries(ImPlotPlot& plot, const ImRect& legend_bb, bool interactable, const ImVec2& pad, const ImVec2& spacing, ImPlotOrientation orn, ImDrawList& DrawList) {
- ImGuiIO& IO = ImGui::GetIO();
+int LegendSortingComp(void* _items, const void* _a, const void* _b) {
+ ImPlotItemGroup* items = (ImPlotItemGroup*)_items;
+ const int a = *(const int*)_a;
+ const int b = *(const int*)_b;
+ const char* label_a = items->GetLegendLabel(a);
+ const char* label_b = items->GetLegendLabel(b);
+ return strcmp(label_a,label_b);
+}
+
+bool ShowLegendEntries(ImPlotItemGroup& items, const ImRect& legend_bb, bool hovered, const ImVec2& pad, const ImVec2& spacing, bool vertical, ImDrawList& DrawList) {
// vars
const float txt_ht = ImGui::GetTextLineHeight();
const float icon_size = txt_ht;
@@ -618,13 +585,29 @@ void ShowLegendEntries(ImPlotPlot& plot, const ImRect& legend_bb, bool interacta
ImU32 col_txt_dis = ImAlphaU32(col_txt, 0.25f);
// render each legend item
float sum_label_width = 0;
- for (int i = 0; i < plot.GetLegendCount(); ++i) {
- ImPlotItem* item = plot.GetLegendItem(i);
- const char* label = plot.GetLegendLabel(i);
+ bool any_item_hovered = false;
+
+ const int num_items = items.GetLegendCount();
+ if (num_items < 1)
+ return hovered;
+ // ImVector<int>& indices = GImPlot->TempInt1;
+ // indices.resize(num_items);
+ // // bool sort = true;
+ // // if (sort && num_items > 1) {
+ // // qsort_s(indices.Data, num_items, sizeof(int), LegendSortingComp, &items);
+ // // }
+ // // else {
+ // // for (int i = 0; i < num_items; ++i)
+ // // indices[i] = i;
+ // // }
+ for (int i = 0; i < num_items; ++i) {
+ const int idx = i; //indices[i];
+ ImPlotItem* item = items.GetLegendItem(idx);
+ const char* label = items.GetLegendLabel(idx);
const float label_width = ImGui::CalcTextSize(label, NULL, true).x;
- const ImVec2 top_left = orn == ImPlotOrientation_Vertical ?
- legend_bb.Min + pad + ImVec2(0, i * (txt_ht + spacing.y)) :
- legend_bb.Min + pad + ImVec2(i * (icon_size + spacing.x) + sum_label_width, 0);
+ const ImVec2 top_left = vertical ?
+ legend_bb.Min + pad + ImVec2(0, i * (txt_ht + spacing.y)) :
+ legend_bb.Min + pad + ImVec2(i * (icon_size + spacing.x) + sum_label_width, 0);
sum_label_width += label_width;
ImRect icon_bb;
icon_bb.Min = top_left + ImVec2(icon_shrink,icon_shrink);
@@ -632,53 +615,70 @@ void ShowLegendEntries(ImPlotPlot& plot, const ImRect& legend_bb, bool interacta
ImRect label_bb;
label_bb.Min = top_left;
label_bb.Max = top_left + ImVec2(label_width + icon_size, icon_size);
- ImU32 col_hl_txt;
+ ImU32 col_txt_hl;
ImU32 col_item = ImAlphaU32(item->Color,1);
- if (interactable && (icon_bb.Contains(IO.MousePos) || label_bb.Contains(IO.MousePos))) {
+
+ ImRect button_bb(icon_bb.Min, label_bb.Max);
+
+
+ bool item_hov = false;
+ bool item_hld = false;
+ bool item_clk = ImHasFlag(items.Legend.Flags, ImPlotLegendFlags_NoButtons)
+ ? false
+ : ImGui::ButtonBehavior(button_bb, item->ID, &item_hov, &item_hld);
+
+ if (item_clk)
+ item->Show = !item->Show;
+
+
+ const bool can_hover = (item_hov)
+ && (!ImHasFlag(items.Legend.Flags, ImPlotLegendFlags_NoHighlightItem)
+ || !ImHasFlag(items.Legend.Flags, ImPlotLegendFlags_NoHighlightAxis));
+
+ if (can_hover) {
+ item->LegendHoverRect.Min = icon_bb.Min;
+ item->LegendHoverRect.Max = label_bb.Max;
item->LegendHovered = true;
- col_hl_txt = ImMixU32(col_txt, col_item, 64);
- }
- else {
- // item->LegendHovered = false;
- col_hl_txt = ImGui::GetColorU32(col_txt);
- }
- ImU32 iconColor;
- if (interactable && icon_bb.Contains(IO.MousePos)) {
- ImU32 col_alpha = ImAlphaU32(col_item,0.5f);
- iconColor = item->Show ? col_alpha : ImGui::GetColorU32(ImGuiCol_TextDisabled, 0.5f);
- if (IO.MouseClicked[0])
- item->Show = !item->Show;
+ col_txt_hl = ImMixU32(col_txt, col_item, 64);
+ any_item_hovered = true;
}
else {
- iconColor = item->Show ? col_item : col_txt_dis;
+ col_txt_hl = ImGui::GetColorU32(col_txt);
}
- DrawList.AddRectFilled(icon_bb.Min, icon_bb.Max, iconColor, 1);
+ ImU32 col_icon;
+ if (item_hld)
+ col_icon = item->Show ? ImAlphaU32(col_item,0.5f) : ImGui::GetColorU32(ImGuiCol_TextDisabled, 0.5f);
+ else if (item_hov)
+ col_icon = item->Show ? ImAlphaU32(col_item,0.75f) : ImGui::GetColorU32(ImGuiCol_TextDisabled, 0.75f);
+ else
+ col_icon = item->Show ? col_item : col_txt_dis;
+
+ DrawList.AddRectFilled(icon_bb.Min, icon_bb.Max, col_icon);
const char* text_display_end = ImGui::FindRenderedTextEnd(label, NULL);
if (label != text_display_end)
- DrawList.AddText(top_left + ImVec2(icon_size, 0), item->Show ? col_hl_txt : col_txt_dis, label, text_display_end);
+ DrawList.AddText(top_left + ImVec2(icon_size, 0), item->Show ? col_txt_hl : col_txt_dis, label, text_display_end);
}
+ return hovered && !any_item_hovered;
}
//-----------------------------------------------------------------------------
// Tick Utils
//-----------------------------------------------------------------------------
-void AddTicksDefault(const ImPlotRange& range, float pix, ImPlotOrientation orn, ImPlotTickCollection& ticks, const char* fmt) {
+static const float TICK_FILL_X = 0.8f;
+static const float TICK_FILL_Y = 1.0f;
+
+void AddTicksDefault(const ImPlotRange& range, float pix, bool vertical, ImPlotTickCollection& ticks, ImPlotFormatter formatter, void* data) {
const int idx0 = ticks.Size;
const int nMinor = 10;
- const int nMajor = ImMax(2, (int)IM_ROUND(pix / (orn == ImPlotOrientation_Horizontal ? 400.0f : 300.0f)));
+ const int nMajor = ImMax(2, (int)IM_ROUND(pix / (vertical ? 300.0f : 400.0f)));
const double nice_range = NiceNum(range.Size() * 0.99, false);
const double interval = NiceNum(nice_range / (nMajor - 1), true);
const double graphmin = floor(range.Min / interval) * interval;
const double graphmax = ceil(range.Max / interval) * interval;
bool first_major_set = false;
int first_major_idx = 0;
-
- char dummy[32];
- sprintf(dummy,fmt,-ImAbs(interval / nMinor));
- ImVec2 dummy_size = ImGui::CalcTextSize(dummy);
ImVec2 total_size(0,0);
-
for (double major = graphmin; major < graphmax + 0.5 * interval; major += interval) {
// is this zero? combat zero formatting issues
if (major-interval < 0 && major+interval > 0)
@@ -688,19 +688,17 @@ void AddTicksDefault(const ImPlotRange& range, float pix, ImPlotOrientation orn,
first_major_idx = ticks.Size;
first_major_set = true;
}
- ticks.Append(major, true, true, fmt);
- total_size += dummy_size;
+ total_size += ticks.Append(major, true, true, formatter, data).LabelSize;
}
for (int i = 1; i < nMinor; ++i) {
double minor = major + i * interval / nMinor;
if (range.Contains(minor)) {
- ticks.Append(minor, false, true, fmt);
- total_size += dummy_size;
+ total_size += ticks.Append(minor, false, true, formatter, data).LabelSize;
}
}
}
// prune if necessary
- if ((orn == ImPlotOrientation_Horizontal && total_size.x > pix) || (orn == ImPlotOrientation_Vertical && total_size.y > pix)) {
+ if ((!vertical && total_size.x > pix*TICK_FILL_X) || (vertical && total_size.y > pix*TICK_FILL_Y)) {
for (int i = first_major_idx-1; i >= idx0; i -= 2)
ticks.Ticks[i].ShowLabel = false;
for (int i = first_major_idx+1; i < ticks.Size; i += 2)
@@ -708,10 +706,10 @@ void AddTicksDefault(const ImPlotRange& range, float pix, ImPlotOrientation orn,
}
}
-void AddTicksLogarithmic(const ImPlotRange& range, float pix, ImPlotOrientation orn, ImPlotTickCollection& ticks, const char* fmt) {
+void AddTicksLogarithmic(const ImPlotRange& range, float pix, bool vertical, ImPlotTickCollection& ticks, ImPlotFormatter formatter, void* data) {
if (range.Min <= 0 || range.Max <= 0)
return;
- const int nMajor = orn == ImPlotOrientation_Horizontal ? ImMax(2, (int)IM_ROUND(pix * 0.01f)) : ImMax(2, (int)IM_ROUND(pix * 0.02f));
+ const int nMajor = vertical ? ImMax(2, (int)IM_ROUND(pix * 0.02f)) : ImMax(2, (int)IM_ROUND(pix * 0.01f));
double log_min = ImLog10(range.Min);
double log_max = ImLog10(range.Max);
int exp_step = ImMax(1,(int)(log_max - log_min) / nMajor);
@@ -726,7 +724,7 @@ void AddTicksLogarithmic(const ImPlotRange& range, float pix, ImPlotOrientation
double major2 = ImPow(10, (double)(e + 1));
double interval = (major2 - major1) / 9;
if (major1 >= (range.Min - DBL_EPSILON) && major1 <= (range.Max + DBL_EPSILON))
- ticks.Append(major1, true, true, fmt);
+ ticks.Append(major1, true, true, formatter, data);
for (int j = 0; j < exp_step; ++j) {
major1 = ImPow(10, (double)(e+j));
major2 = ImPow(10, (double)(e+j+1));
@@ -734,14 +732,14 @@ void AddTicksLogarithmic(const ImPlotRange& range, float pix, ImPlotOrientation
for (int i = 1; i < (9 + (int)(j < (exp_step - 1))); ++i) {
double minor = major1 + i * interval;
if (minor >= (range.Min - DBL_EPSILON) && minor <= (range.Max + DBL_EPSILON))
- ticks.Append(minor, false, false, fmt);
+ ticks.Append(minor, false, false, formatter, data);
}
}
}
}
-void AddTicksCustom(const double* values, const char* const labels[], int n, ImPlotTickCollection& ticks, const char* fmt) {
+void AddTicksCustom(const double* values, const char* const labels[], int n, ImPlotTickCollection& ticks, ImPlotFormatter formatter, void* data) {
for (int i = 0; i < n; ++i) {
if (labels != NULL) {
ImPlotTick tick(values[i], false, true);
@@ -751,7 +749,7 @@ void AddTicksCustom(const double* values, const char* const labels[], int n, ImP
ticks.Append(tick);
}
else {
- ticks.Append(values[i], false, true, fmt);
+ ticks.Append(values[i], false, true, formatter, data);
}
}
}
@@ -981,6 +979,7 @@ ImPlotTime CombineDateTime(const ImPlotTime& date_part, const ImPlotTime& tod_pa
return t;
}
+// TODO: allow users to define these
static const char* MONTH_NAMES[] = {"January","February","March","April","May","June","July","August","September","October","November","December"};
static const char* WD_ABRVS[] = {"Su","Mo","Tu","We","Th","Fr","Sa"};
static const char* MONTH_ABRVS[] = {"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
@@ -995,14 +994,14 @@ int FormatTime(const ImPlotTime& t, char* buffer, int size, ImPlotTimeFmt fmt, b
if (use_24_hr_clk) {
const int hr = Tm.tm_hour;
switch(fmt) {
- case ImPlotTimeFmt_Us: return snprintf(buffer, size, ".%03d %03d", ms, us);
- case ImPlotTimeFmt_SUs: return snprintf(buffer, size, ":%02d.%03d %03d", sec, ms, us);
- case ImPlotTimeFmt_SMs: return snprintf(buffer, size, ":%02d.%03d", sec, ms);
- case ImPlotTimeFmt_S: return snprintf(buffer, size, ":%02d", sec);
- case ImPlotTimeFmt_HrMinSMs: return snprintf(buffer, size, "%02d:%02d:%02d.%03d", hr, min, sec, ms);
- case ImPlotTimeFmt_HrMinS: return snprintf(buffer, size, "%02d:%02d:%02d", hr, min, sec);
- case ImPlotTimeFmt_HrMin: return snprintf(buffer, size, "%02d:%02d", hr, min);
- case ImPlotTimeFmt_Hr: return snprintf(buffer, size, "%02d:00", hr);
+ case ImPlotTimeFmt_Us: return ImFormatString(buffer, size, ".%03d %03d", ms, us);
+ case ImPlotTimeFmt_SUs: return ImFormatString(buffer, size, ":%02d.%03d %03d", sec, ms, us);
+ case ImPlotTimeFmt_SMs: return ImFormatString(buffer, size, ":%02d.%03d", sec, ms);
+ case ImPlotTimeFmt_S: return ImFormatString(buffer, size, ":%02d", sec);
+ case ImPlotTimeFmt_HrMinSMs: return ImFormatString(buffer, size, "%02d:%02d:%02d.%03d", hr, min, sec, ms);
+ case ImPlotTimeFmt_HrMinS: return ImFormatString(buffer, size, "%02d:%02d:%02d", hr, min, sec);
+ case ImPlotTimeFmt_HrMin: return ImFormatString(buffer, size, "%02d:%02d", hr, min);
+ case ImPlotTimeFmt_Hr: return ImFormatString(buffer, size, "%02d:00", hr);
default: return 0;
}
}
@@ -1010,14 +1009,14 @@ int FormatTime(const ImPlotTime& t, char* buffer, int size, ImPlotTimeFmt fmt, b
const char* ap = Tm.tm_hour < 12 ? "am" : "pm";
const int hr = (Tm.tm_hour == 0 || Tm.tm_hour == 12) ? 12 : Tm.tm_hour % 12;
switch(fmt) {
- case ImPlotTimeFmt_Us: return snprintf(buffer, size, ".%03d %03d", ms, us);
- case ImPlotTimeFmt_SUs: return snprintf(buffer, size, ":%02d.%03d %03d", sec, ms, us);
- case ImPlotTimeFmt_SMs: return snprintf(buffer, size, ":%02d.%03d", sec, ms);
- case ImPlotTimeFmt_S: return snprintf(buffer, size, ":%02d", sec);
- case ImPlotTimeFmt_HrMinSMs: return snprintf(buffer, size, "%d:%02d:%02d.%03d%s", hr, min, sec, ms, ap);
- case ImPlotTimeFmt_HrMinS: return snprintf(buffer, size, "%d:%02d:%02d%s", hr, min, sec, ap);
- case ImPlotTimeFmt_HrMin: return snprintf(buffer, size, "%d:%02d%s", hr, min, ap);
- case ImPlotTimeFmt_Hr: return snprintf(buffer, size, "%d%s", hr, ap);
+ case ImPlotTimeFmt_Us: return ImFormatString(buffer, size, ".%03d %03d", ms, us);
+ case ImPlotTimeFmt_SUs: return ImFormatString(buffer, size, ":%02d.%03d %03d", sec, ms, us);
+ case ImPlotTimeFmt_SMs: return ImFormatString(buffer, size, ":%02d.%03d", sec, ms);
+ case ImPlotTimeFmt_S: return ImFormatString(buffer, size, ":%02d", sec);
+ case ImPlotTimeFmt_HrMinSMs: return ImFormatString(buffer, size, "%d:%02d:%02d.%03d%s", hr, min, sec, ms, ap);
+ case ImPlotTimeFmt_HrMinS: return ImFormatString(buffer, size, "%d:%02d:%02d%s", hr, min, sec, ap);
+ case ImPlotTimeFmt_HrMin: return ImFormatString(buffer, size, "%d:%02d%s", hr, min, ap);
+ case ImPlotTimeFmt_Hr: return ImFormatString(buffer, size, "%d%s", hr, ap);
default: return 0;
}
}
@@ -1032,21 +1031,21 @@ int FormatDate(const ImPlotTime& t, char* buffer, int size, ImPlotDateFmt fmt, b
const int yr = year % 100;
if (use_iso_8601) {
switch (fmt) {
- case ImPlotDateFmt_DayMo: return snprintf(buffer, size, "--%02d-%02d", mon, day);
- case ImPlotDateFmt_DayMoYr: return snprintf(buffer, size, "%d-%02d-%02d", year, mon, day);
- case ImPlotDateFmt_MoYr: return snprintf(buffer, size, "%d-%02d", year, mon);
- case ImPlotDateFmt_Mo: return snprintf(buffer, size, "--%02d", mon);
- case ImPlotDateFmt_Yr: return snprintf(buffer, size, "%d", year);
+ case ImPlotDateFmt_DayMo: return ImFormatString(buffer, size, "--%02d-%02d", mon, day);
+ case ImPlotDateFmt_DayMoYr: return ImFormatString(buffer, size, "%d-%02d-%02d", year, mon, day);
+ case ImPlotDateFmt_MoYr: return ImFormatString(buffer, size, "%d-%02d", year, mon);
+ case ImPlotDateFmt_Mo: return ImFormatString(buffer, size, "--%02d", mon);
+ case ImPlotDateFmt_Yr: return ImFormatString(buffer, size, "%d", year);
default: return 0;
}
}
else {
switch (fmt) {
- case ImPlotDateFmt_DayMo: return snprintf(buffer, size, "%d/%d", mon, day);
- case ImPlotDateFmt_DayMoYr: return snprintf(buffer, size, "%d/%d/%02d", mon, day, yr);
- case ImPlotDateFmt_MoYr: return snprintf(buffer, size, "%s %d", MONTH_ABRVS[Tm.tm_mon], year);
- case ImPlotDateFmt_Mo: return snprintf(buffer, size, "%s", MONTH_ABRVS[Tm.tm_mon]);
- case ImPlotDateFmt_Yr: return snprintf(buffer, size, "%d", year);
+ case ImPlotDateFmt_DayMo: return ImFormatString(buffer, size, "%d/%d", mon, day);
+ case ImPlotDateFmt_DayMoYr: return ImFormatString(buffer, size, "%d/%d/%02d", mon, day, yr);
+ case ImPlotDateFmt_MoYr: return ImFormatString(buffer, size, "%s %d", MONTH_ABRVS[Tm.tm_mon], year);
+ case ImPlotDateFmt_Mo: return ImFormatString(buffer, size, "%s", MONTH_ABRVS[Tm.tm_mon]);
+ case ImPlotDateFmt_Yr: return ImFormatString(buffer, size, "%d", year);
default: return 0;
}
}
@@ -1237,38 +1236,469 @@ void AddTicksTime(const ImPlotRange& range, float plot_width, ImPlotTickCollecti
}
//-----------------------------------------------------------------------------
+// Context Menu
+//-----------------------------------------------------------------------------
+
+template <typename F>
+bool DragFloat(const char*, F*, float, F, F) {
+ return false;
+}
+
+template <>
+bool DragFloat<double>(const char* label, double* v, float v_speed, double v_min, double v_max) {
+ return ImGui::DragScalar(label, ImGuiDataType_Double, v, v_speed, &v_min, &v_max, "%.3f", 1);
+}
+
+template <>
+bool DragFloat<float>(const char* label, float* v, float v_speed, float v_min, float v_max) {
+ return ImGui::DragScalar(label, ImGuiDataType_Float, v, v_speed, &v_min, &v_max, "%.3f", 1);
+}
+
+inline void BeginDisabledControls(bool cond) {
+ if (cond) {
+ ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true);
+ ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.25f);
+ }
+}
+
+inline void EndDisabledControls(bool cond) {
+ if (cond) {
+ ImGui::PopItemFlag();
+ ImGui::PopStyleVar();
+ }
+}
+
+void ShowAxisContextMenu(ImPlotAxis& axis, ImPlotAxis* equal_axis, bool time_allowed) {
+
+ ImGui::PushItemWidth(75);
+ bool always_locked = axis.IsRangeLocked() || axis.IsAutoFitting();
+ bool label = axis.HasLabel();
+ bool grid = axis.HasGridLines();
+ bool ticks = axis.HasTickMarks();
+ bool labels = axis.HasTickLabels();
+ double drag_speed = (axis.Range.Size() <= DBL_EPSILON) ? DBL_EPSILON * 1.0e+13 : 0.01 * axis.Range.Size(); // recover from almost equal axis limits.
+
+ if (axis.IsTime()) {
+ ImPlotTime tmin = ImPlotTime::FromDouble(axis.Range.Min);
+ ImPlotTime tmax = ImPlotTime::FromDouble(axis.Range.Max);
+
+ BeginDisabledControls(always_locked);
+ ImGui::CheckboxFlags("##LockMin", (unsigned int*)&axis.Flags, ImPlotAxisFlags_LockMin);
+ EndDisabledControls(always_locked);
+ ImGui::SameLine();
+ BeginDisabledControls(axis.IsLockedMin() || always_locked);
+ if (ImGui::BeginMenu("Min Time")) {
+ if (ShowTimePicker("mintime", &tmin)) {
+ if (tmin >= tmax)
+ tmax = AddTime(tmin, ImPlotTimeUnit_S, 1);
+ axis.SetRange(tmin.ToDouble(),tmax.ToDouble());
+ }
+ ImGui::Separator();
+ if (ShowDatePicker("mindate",&axis.PickerLevel,&axis.PickerTimeMin,&tmin,&tmax)) {
+ tmin = CombineDateTime(axis.PickerTimeMin, tmin);
+ if (tmin >= tmax)
+ tmax = AddTime(tmin, ImPlotTimeUnit_S, 1);
+ axis.SetRange(tmin.ToDouble(), tmax.ToDouble());
+ }
+ ImGui::EndMenu();
+ }
+ EndDisabledControls(axis.IsLockedMin() || always_locked);
+
+ BeginDisabledControls(always_locked);
+ ImGui::CheckboxFlags("##LockMax", (unsigned int*)&axis.Flags, ImPlotAxisFlags_LockMax);
+ EndDisabledControls(always_locked);
+ ImGui::SameLine();
+ BeginDisabledControls(axis.IsLockedMax() || always_locked);
+ if (ImGui::BeginMenu("Max Time")) {
+ if (ShowTimePicker("maxtime", &tmax)) {
+ if (tmax <= tmin)
+ tmin = AddTime(tmax, ImPlotTimeUnit_S, -1);
+ axis.SetRange(tmin.ToDouble(),tmax.ToDouble());
+ }
+ ImGui::Separator();
+ if (ShowDatePicker("maxdate",&axis.PickerLevel,&axis.PickerTimeMax,&tmin,&tmax)) {
+ tmax = CombineDateTime(axis.PickerTimeMax, tmax);
+ if (tmax <= tmin)
+ tmin = AddTime(tmax, ImPlotTimeUnit_S, -1);
+ axis.SetRange(tmin.ToDouble(), tmax.ToDouble());
+ }
+ ImGui::EndMenu();
+ }
+ EndDisabledControls(axis.IsLockedMax() || always_locked);
+ }
+ else {
+ BeginDisabledControls(always_locked);
+ ImGui::CheckboxFlags("##LockMin", (unsigned int*)&axis.Flags, ImPlotAxisFlags_LockMin);
+ EndDisabledControls(always_locked);
+ ImGui::SameLine();
+ BeginDisabledControls(axis.IsLockedMin() || always_locked);
+ double temp_min = axis.Range.Min;
+ if (DragFloat("Min", &temp_min, (float)drag_speed, -HUGE_VAL, axis.Range.Max - DBL_EPSILON)) {
+ axis.SetMin(temp_min,true);
+ if (equal_axis != NULL)
+ equal_axis->SetAspect(axis.GetAspect());
+ }
+ EndDisabledControls(axis.IsLockedMin() || always_locked);
+
+ BeginDisabledControls(always_locked);
+ ImGui::CheckboxFlags("##LockMax", (unsigned int*)&axis.Flags, ImPlotAxisFlags_LockMax);
+ EndDisabledControls(always_locked);
+ ImGui::SameLine();
+ BeginDisabledControls(axis.IsLockedMax() || always_locked);
+ double temp_max = axis.Range.Max;
+ if (DragFloat("Max", &temp_max, (float)drag_speed, axis.Range.Min + DBL_EPSILON, HUGE_VAL)) {
+ axis.SetMax(temp_max,true);
+ if (equal_axis != NULL)
+ equal_axis->SetAspect(axis.GetAspect());
+ }
+ EndDisabledControls(axis.IsLockedMax() || always_locked);
+ }
+
+ ImGui::Separator();
+
+ ImGui::CheckboxFlags("Auto-Fit",(unsigned int*)&axis.Flags, ImPlotAxisFlags_AutoFit);
+ BeginDisabledControls(axis.IsTime() && time_allowed);
+ ImGui::CheckboxFlags("Log Scale",(unsigned int*)&axis.Flags, ImPlotAxisFlags_LogScale);
+ EndDisabledControls(axis.IsTime() && time_allowed);
+ if (time_allowed) {
+ BeginDisabledControls(axis.IsLog());
+ ImGui::CheckboxFlags("Time",(unsigned int*)&axis.Flags, ImPlotAxisFlags_Time);
+ EndDisabledControls(axis.IsLog());
+ }
+ ImGui::Separator();
+ ImGui::CheckboxFlags("Invert",(unsigned int*)&axis.Flags, ImPlotAxisFlags_Invert);
+ ImGui::CheckboxFlags("Opposite",(unsigned int*)&axis.Flags, ImPlotAxisFlags_Opposite);
+ ImGui::Separator();
+ BeginDisabledControls(axis.LabelOffset == -1);
+ if (ImGui::Checkbox("Label", &label))
+ ImFlipFlag(axis.Flags, ImPlotAxisFlags_NoLabel);
+ EndDisabledControls(axis.LabelOffset == -1);
+ if (ImGui::Checkbox("Grid Lines", &grid))
+ ImFlipFlag(axis.Flags, ImPlotAxisFlags_NoGridLines);
+ if (ImGui::Checkbox("Tick Marks", &ticks))
+ ImFlipFlag(axis.Flags, ImPlotAxisFlags_NoTickMarks);
+ if (ImGui::Checkbox("Tick Labels", &labels))
+ ImFlipFlag(axis.Flags, ImPlotAxisFlags_NoTickLabels);
+
+}
+
+bool ShowLegendContextMenu(ImPlotLegend& legend, bool visible) {
+ const float s = ImGui::GetFrameHeight();
+ bool ret = false;
+ if (ImGui::Checkbox("Show",&visible))
+ ret = true;
+ if (legend.CanGoInside)
+ ImGui::CheckboxFlags("Outside",(unsigned int*)&legend.Flags, ImPlotLegendFlags_Outside);
+ if (ImGui::RadioButton("H", ImHasFlag(legend.Flags, ImPlotLegendFlags_Horizontal)))
+ legend.Flags |= ImPlotLegendFlags_Horizontal;
+ ImGui::SameLine();
+ if (ImGui::RadioButton("V", !ImHasFlag(legend.Flags, ImPlotLegendFlags_Horizontal)))
+ legend.Flags &= ~ImPlotLegendFlags_Horizontal;
+ ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(2,2));
+ if (ImGui::Button("NW",ImVec2(1.5f*s,s))) { legend.Location = ImPlotLocation_NorthWest; } ImGui::SameLine();
+ if (ImGui::Button("N", ImVec2(1.5f*s,s))) { legend.Location = ImPlotLocation_North; } ImGui::SameLine();
+ if (ImGui::Button("NE",ImVec2(1.5f*s,s))) { legend.Location = ImPlotLocation_NorthEast; }
+ if (ImGui::Button("W", ImVec2(1.5f*s,s))) { legend.Location = ImPlotLocation_West; } ImGui::SameLine();
+ if (ImGui::InvisibleButton("C", ImVec2(1.5f*s,s))) { } ImGui::SameLine();
+ if (ImGui::Button("E", ImVec2(1.5f*s,s))) { legend.Location = ImPlotLocation_East; }
+ if (ImGui::Button("SW",ImVec2(1.5f*s,s))) { legend.Location = ImPlotLocation_SouthWest; } ImGui::SameLine();
+ if (ImGui::Button("S", ImVec2(1.5f*s,s))) { legend.Location = ImPlotLocation_South; } ImGui::SameLine();
+ if (ImGui::Button("SE",ImVec2(1.5f*s,s))) { legend.Location = ImPlotLocation_SouthEast; }
+ ImGui::PopStyleVar();
+ return ret;
+}
+
+void ShowSubplotsContextMenu(ImPlotSubplot& subplot) {
+ if ((ImGui::BeginMenu("Linking"))) {
+ if (ImGui::MenuItem("Link Rows",NULL,ImHasFlag(subplot.Flags, ImPlotSubplotFlags_LinkRows)))
+ ImFlipFlag(subplot.Flags, ImPlotSubplotFlags_LinkRows);
+ if (ImGui::MenuItem("Link Cols",NULL,ImHasFlag(subplot.Flags, ImPlotSubplotFlags_LinkCols)))
+ ImFlipFlag(subplot.Flags, ImPlotSubplotFlags_LinkCols);
+ if (ImGui::MenuItem("Link All X",NULL,ImHasFlag(subplot.Flags, ImPlotSubplotFlags_LinkAllX)))
+ ImFlipFlag(subplot.Flags, ImPlotSubplotFlags_LinkAllX);
+ if (ImGui::MenuItem("Link All Y",NULL,ImHasFlag(subplot.Flags, ImPlotSubplotFlags_LinkAllY)))
+ ImFlipFlag(subplot.Flags, ImPlotSubplotFlags_LinkAllY);
+ ImGui::EndMenu();
+ }
+ if ((ImGui::BeginMenu("Settings"))) {
+ BeginDisabledControls(!subplot.HasTitle);
+ if (ImGui::MenuItem("Title",NULL,subplot.HasTitle && !ImHasFlag(subplot.Flags, ImPlotSubplotFlags_NoTitle)))
+ ImFlipFlag(subplot.Flags, ImPlotSubplotFlags_NoTitle);
+ EndDisabledControls(!subplot.HasTitle);
+ if (ImGui::MenuItem("Resizable",NULL,!ImHasFlag(subplot.Flags, ImPlotSubplotFlags_NoResize)))
+ ImFlipFlag(subplot.Flags, ImPlotSubplotFlags_NoResize);
+ if (ImGui::MenuItem("Align",NULL,!ImHasFlag(subplot.Flags, ImPlotSubplotFlags_NoAlign)))
+ ImFlipFlag(subplot.Flags, ImPlotSubplotFlags_NoAlign);
+ if (ImGui::MenuItem("Share Items",NULL,ImHasFlag(subplot.Flags, ImPlotSubplotFlags_ShareItems)))
+ ImFlipFlag(subplot.Flags, ImPlotSubplotFlags_ShareItems);
+ ImGui::EndMenu();
+ }
+}
+
+void ShowPlotContextMenu(ImPlotPlot& plot) {
+ const bool owns_legend = GImPlot->CurrentItems == &plot.Items;
+ const bool equal = ImHasFlag(plot.Flags, ImPlotFlags_Equal);
+
+ char buf[16] = {};
+
+ for (int i = 0; i < IMPLOT_NUM_X_AXES; i++) {
+ ImPlotAxis& x_axis = plot.XAxis(i);
+ if (!x_axis.Enabled || !x_axis.HasMenus())
+ continue;
+ ImGui::PushID(i);
+ ImFormatString(buf, sizeof(buf) - 1, i == 0 ? "X-Axis" : "X-Axis %d", i + 1);
+ if (ImGui::BeginMenu(x_axis.HasLabel() ? plot.GetAxisLabel(x_axis) : buf)) {
+ ShowAxisContextMenu(x_axis, equal ? x_axis.OrthoAxis : NULL, false);
+ ImGui::EndMenu();
+ }
+ ImGui::PopID();
+ }
+
+ for (int i = 0; i < IMPLOT_NUM_Y_AXES; i++) {
+ ImPlotAxis& y_axis = plot.YAxis(i);
+ if (!y_axis.Enabled || !y_axis.HasMenus())
+ continue;
+ ImGui::PushID(i);
+ ImFormatString(buf, sizeof(buf) - 1, i == 0 ? "Y-Axis" : "Y-Axis %d", i + 1);
+ if (ImGui::BeginMenu(y_axis.HasLabel() ? plot.GetAxisLabel(y_axis) : buf)) {
+ ShowAxisContextMenu(y_axis, equal ? y_axis.OrthoAxis : NULL, false);
+ ImGui::EndMenu();
+ }
+ ImGui::PopID();
+ }
+
+ ImGui::Separator();
+ if (!ImHasFlag(GImPlot->CurrentItems->Legend.Flags, ImPlotLegendFlags_NoMenus)) {
+ if ((ImGui::BeginMenu("Legend"))) {
+ if (owns_legend) {
+ if (ShowLegendContextMenu(plot.Items.Legend, !ImHasFlag(plot.Flags, ImPlotFlags_NoLegend)))
+ ImFlipFlag(plot.Flags, ImPlotFlags_NoLegend);
+ }
+ else if (GImPlot->CurrentSubplot != NULL) {
+ if (ShowLegendContextMenu(GImPlot->CurrentSubplot->Items.Legend, !ImHasFlag(GImPlot->CurrentSubplot->Flags, ImPlotSubplotFlags_NoLegend)))
+ ImFlipFlag(GImPlot->CurrentSubplot->Flags, ImPlotSubplotFlags_NoLegend);
+ }
+ ImGui::EndMenu();
+ }
+ }
+ if ((ImGui::BeginMenu("Settings"))) {
+ if (ImGui::MenuItem("Anti-Aliased Lines",NULL,ImHasFlag(plot.Flags, ImPlotFlags_AntiAliased)))
+ ImFlipFlag(plot.Flags, ImPlotFlags_AntiAliased);
+ if (ImGui::MenuItem("Equal", NULL, ImHasFlag(plot.Flags, ImPlotFlags_Equal)))
+ ImFlipFlag(plot.Flags, ImPlotFlags_Equal);
+ if (ImGui::MenuItem("Box Select",NULL,!ImHasFlag(plot.Flags, ImPlotFlags_NoBoxSelect)))
+ ImFlipFlag(plot.Flags, ImPlotFlags_NoBoxSelect);
+ BeginDisabledControls(plot.TitleOffset == -1);
+ if (ImGui::MenuItem("Title",NULL,plot.HasTitle()))
+ ImFlipFlag(plot.Flags, ImPlotFlags_NoTitle);
+ EndDisabledControls(plot.TitleOffset == -1);
+ if (ImGui::MenuItem("Mouse Position",NULL,!ImHasFlag(plot.Flags, ImPlotFlags_NoMouseText)))
+ ImFlipFlag(plot.Flags, ImPlotFlags_NoMouseText);
+ if (ImGui::MenuItem("Crosshairs",NULL,ImHasFlag(plot.Flags, ImPlotFlags_Crosshairs)))
+ ImFlipFlag(plot.Flags, ImPlotFlags_Crosshairs);
+ ImGui::EndMenu();
+ }
+ if (GImPlot->CurrentSubplot != NULL && !ImHasFlag(GImPlot->CurrentPlot->Flags, ImPlotSubplotFlags_NoMenus)) {
+ ImGui::Separator();
+ if ((ImGui::BeginMenu("Subplots"))) {
+ ShowSubplotsContextMenu(*GImPlot->CurrentSubplot);
+ ImGui::EndMenu();
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
// Axis Utils
//-----------------------------------------------------------------------------
-static inline int AxisPrecision(const ImPlotAxis& axis, const ImPlotTickCollection& ticks) {
- const double range = ticks.Size > 1 ? (ticks.Ticks[1].PlotPos - ticks.Ticks[0].PlotPos) : axis.Range.Size();
+static inline void DefaultFormatter(double value, char* buff, int size, void* data) {
+ char* fmt = (char*)data;
+ ImFormatString(buff, size, fmt, value);
+}
+
+static inline int AxisPrecision(const ImPlotAxis& axis) {
+ const double range = axis.Ticks.Size > 1 ? (axis.Ticks.Ticks[1].PlotPos - axis.Ticks.Ticks[0].PlotPos) : axis.Range.Size();
return Precision(range);
}
-static inline double RoundAxisValue(const ImPlotAxis& axis, const ImPlotTickCollection& ticks, double value) {
- return RoundTo(value, AxisPrecision(axis,ticks));
+static inline double RoundAxisValue(const ImPlotAxis& axis, double value) {
+ return RoundTo(value, AxisPrecision(axis));
}
-int LabelAxisValue(const ImPlotAxis& axis, const ImPlotTickCollection& ticks, double value, char* buff, int size) {
+void LabelAxisValue(const ImPlotAxis& axis, double value, char* buff, int size, bool round) {
ImPlotContext& gp = *GImPlot;
- if (ImHasFlag(axis.Flags, ImPlotAxisFlags_Time)) {
- ImPlotTimeUnit unit = (axis.Orientation == ImPlotOrientation_Horizontal)
- ? GetUnitForRange(axis.Range.Size() / (gp.CurrentPlot->PlotRect.GetWidth() / 100))
- : GetUnitForRange(axis.Range.Size() / (gp.CurrentPlot->PlotRect.GetHeight() / 100));
- return FormatDateTime(ImPlotTime::FromDouble(value), buff, size, GetDateTimeFmt(TimeFormatMouseCursor, unit));
+ if (axis.IsTime()) {
+ ImPlotTimeUnit unit = axis.Vertical
+ ? GetUnitForRange(axis.Range.Size() / (gp.CurrentPlot->PlotRect.GetHeight() / 100)) // TODO: magic value!
+ : GetUnitForRange(axis.Range.Size() / (gp.CurrentPlot->PlotRect.GetWidth() / 100)); // TODO: magic value!
+ FormatDateTime(ImPlotTime::FromDouble(value), buff, size, GetDateTimeFmt(TimeFormatMouseCursor, unit));
}
else {
- double range = ticks.Size > 1 ? (ticks.Ticks[1].PlotPos - ticks.Ticks[0].PlotPos) : axis.Range.Size();
- return snprintf(buff, size, "%.*f", Precision(range), value);
+ if (round)
+ value = RoundAxisValue(axis, value);
+ ImPlotFormatter formatter = axis.Formatter ? axis.Formatter : DefaultFormatter;
+ void* data = (axis.Formatter && axis.FormatterData) ? axis.FormatterData : axis.HasFormatSpec ? (void*)axis.FormatSpec : (void*)IMPLOT_LABEL_FORMAT;
+ formatter(value, buff, size, data);
}
}
-void UpdateAxisColors(int axis_flag, ImPlotAxis* axis) {
- const ImVec4 col_label = GetStyleColorVec4(axis_flag);
- const ImVec4 col_grid = GetStyleColorVec4(axis_flag + 1);
- axis->ColorMaj = ImGui::GetColorU32(col_grid);
- axis->ColorMin = ImGui::GetColorU32(col_grid*ImVec4(1,1,1,GImPlot->Style.MinorAlpha));
- axis->ColorTxt = ImGui::GetColorU32(col_label);
+void UpdateAxisColors(ImPlotAxis& axis) {
+ const ImVec4 col_grid = GetStyleColorVec4(ImPlotCol_AxisGrid);
+ axis.ColorMaj = ImGui::GetColorU32(col_grid);
+ axis.ColorMin = ImGui::GetColorU32(col_grid*ImVec4(1,1,1,GImPlot->Style.MinorAlpha));
+ axis.ColorTick = GetStyleColorU32(ImPlotCol_AxisTick);
+ axis.ColorTxt = GetStyleColorU32(ImPlotCol_AxisText);
+ axis.ColorBg = GetStyleColorU32(ImPlotCol_AxisBg);
+ axis.ColorHov = GetStyleColorU32(ImPlotCol_AxisBgHovered);
+ axis.ColorAct = GetStyleColorU32(ImPlotCol_AxisBgActive);
+ // axis.ColorHiLi = IM_COL32_BLACK_TRANS;
+}
+
+void PadAndDatumAxesX(ImPlotPlot& plot, float& pad_T, float& pad_B, ImPlotAlignmentData* align) {
+
+ ImPlotContext& gp = *GImPlot;
+
+ const float T = ImGui::GetTextLineHeight();
+ const float P = gp.Style.LabelPadding.y;
+ const float K = gp.Style.MinorTickLen.x;
+
+ int count_T = 0;
+ int count_B = 0;
+ float last_T = plot.AxesRect.Min.y;
+ float last_B = plot.AxesRect.Max.y;
+
+ for (int i = IMPLOT_NUM_X_AXES; i-- > 0;) { // FYI: can iterate forward
+ ImPlotAxis& axis = plot.XAxis(i);
+ if (!axis.Enabled)
+ continue;
+ const bool label = axis.HasLabel();
+ const bool ticks = axis.HasTickLabels();
+ const bool opp = axis.IsOpposite();
+ const bool time = axis.IsTime();
+ if (opp) {
+ if (count_T++ > 0)
+ pad_T += K + P;
+ if (label)
+ pad_T += T + P;
+ if (ticks)
+ pad_T += ImMax(T, axis.Ticks.MaxSize.y) + P + (time ? T + P : 0);
+ axis.Datum1 = plot.CanvasRect.Min.y + pad_T;
+ axis.Datum2 = last_T;
+ last_T = axis.Datum1;
+ }
+ else {
+ if (count_B++ > 0)
+ pad_B += K + P;
+ if (label)
+ pad_B += T + P;
+ if (ticks)
+ pad_B += ImMax(T, axis.Ticks.MaxSize.y) + P + (time ? T + P : 0);
+ axis.Datum1 = plot.CanvasRect.Max.y - pad_B;
+ axis.Datum2 = last_B;
+ last_B = axis.Datum1;
+ }
+ }
+
+ if (align) {
+ count_T = count_B = 0;
+ float delta_T, delta_B;
+ align->Update(pad_T,pad_B,delta_T,delta_B);
+ for (int i = IMPLOT_NUM_X_AXES; i-- > 0;) {
+ ImPlotAxis& axis = plot.XAxis(i);
+ if (!axis.Enabled)
+ continue;
+ if (axis.IsOpposite()) {
+ axis.Datum1 += delta_T;
+ axis.Datum2 += count_T++ > 1 ? delta_T : 0;
+ }
+ else {
+ axis.Datum1 -= delta_B;
+ axis.Datum2 -= count_B++ > 1 ? delta_B : 0;
+ }
+ }
+ }
+}
+
+void PadAndDatumAxesY(ImPlotPlot& plot, float& pad_L, float& pad_R, ImPlotAlignmentData* align) {
+
+ // [ pad_L ] [ pad_R ]
+ // .................CanvasRect................
+ // :TPWPK.PTPWP _____PlotRect____ PWPTP.KPWPT:
+ // :A # |- A # |- -| # A -| # A:
+ // :X | X | | X | x:
+ // :I # |- I # |- -| # I -| # I:
+ // :S | S | | S | S:
+ // :3 # |- 0 # |-_______________-| # 1 -| # 2:
+ // :.........................................:
+ //
+ // T = text height
+ // P = label padding
+ // K = minor tick length
+ // W = label width
+
+ ImPlotContext& gp = *GImPlot;
+
+ const float T = ImGui::GetTextLineHeight();
+ const float P = gp.Style.LabelPadding.x;
+ const float K = gp.Style.MinorTickLen.y;
+
+ int count_L = 0;
+ int count_R = 0;
+ float last_L = plot.AxesRect.Min.x;
+ float last_R = plot.AxesRect.Max.x;
+
+ for (int i = IMPLOT_NUM_Y_AXES; i-- > 0;) { // FYI: can iterate forward
+ ImPlotAxis& axis = plot.YAxis(i);
+ if (!axis.Enabled)
+ continue;
+ const bool label = axis.HasLabel();
+ const bool ticks = axis.HasTickLabels();
+ const bool opp = axis.IsOpposite();
+ if (opp) {
+ if (count_R++ > 0)
+ pad_R += K + P;
+ if (label)
+ pad_R += T + P;
+ if (ticks)
+ pad_R += axis.Ticks.MaxSize.x + P;
+ axis.Datum1 = plot.CanvasRect.Max.x - pad_R;
+ axis.Datum2 = last_R;
+ last_R = axis.Datum1;
+ }
+ else {
+ if (count_L++ > 0)
+ pad_L += K + P;
+ if (label)
+ pad_L += T + P;
+ if (ticks)
+ pad_L += axis.Ticks.MaxSize.x + P;
+ axis.Datum1 = plot.CanvasRect.Min.x + pad_L;
+ axis.Datum2 = last_L;
+ last_L = axis.Datum1;
+ }
+ }
+
+ plot.PlotRect.Min.x = plot.CanvasRect.Min.x + pad_L;
+ plot.PlotRect.Max.x = plot.CanvasRect.Max.x - pad_R;
+
+ if (align) {
+ count_L = count_R = 0;
+ float delta_L, delta_R;
+ align->Update(pad_L,pad_R,delta_L,delta_R);
+ for (int i = IMPLOT_NUM_Y_AXES; i-- > 0;) {
+ ImPlotAxis& axis = plot.YAxis(i);
+ if (!axis.Enabled)
+ continue;
+ if (axis.IsOpposite()) {
+ axis.Datum1 -= delta_R;
+ axis.Datum2 -= count_R++ > 1 ? delta_R : 0;
+ }
+ else {
+ axis.Datum1 += delta_L;
+ axis.Datum2 += count_L++ > 1 ? delta_L : 0;
+ }
+ }
+ }
}
//-----------------------------------------------------------------------------
@@ -1282,6 +1712,8 @@ static inline void RenderGridLinesX(ImDrawList& DrawList, const ImPlotTickCollec
col_min = ImGui::ColorConvertFloat4ToU32(col_min4);
for (int t = 0; t < ticks.Size; t++) {
const ImPlotTick& xt = ticks.Ticks[t];
+ if (xt.PixelPos < rect.Min.x || xt.PixelPos > rect.Max.x)
+ continue;
if (xt.Level == 0) {
if (xt.Major)
DrawList.AddLine(ImVec2(xt.PixelPos, rect.Min.y), ImVec2(xt.PixelPos, rect.Max.y), col_maj, size_maj);
@@ -1298,6 +1730,8 @@ static inline void RenderGridLinesY(ImDrawList& DrawList, const ImPlotTickCollec
col_min = ImGui::ColorConvertFloat4ToU32(col_min4);
for (int t = 0; t < ticks.Size; t++) {
const ImPlotTick& yt = ticks.Ticks[t];
+ if (yt.PixelPos < rect.Min.y || yt.PixelPos > rect.Max.y)
+ continue;
if (yt.Major)
DrawList.AddLine(ImVec2(rect.Min.x, yt.PixelPos), ImVec2(rect.Max.x, yt.PixelPos), col_maj, size_maj);
else if (density < 0.2f)
@@ -1313,511 +1747,251 @@ static inline void RenderSelectionRect(ImDrawList& DrawList, const ImVec2& p_min
}
//-----------------------------------------------------------------------------
-// BeginPlot()
+// Input Handling
//-----------------------------------------------------------------------------
-bool BeginPlot(const char* title, const char* x_label, const char* y1_label, const ImVec2& size,
- ImPlotFlags flags, ImPlotAxisFlags x_flags, ImPlotAxisFlags y1_flags, ImPlotAxisFlags y2_flags, ImPlotAxisFlags y3_flags,
- const char* y2_label, const char* y3_label)
-{
- IM_ASSERT_USER_ERROR(GImPlot != NULL, "No current context. Did you call ImPlot::CreateContext() or ImPlot::SetCurrentContext()?");
- ImPlotContext& gp = *GImPlot;
- IM_ASSERT_USER_ERROR(gp.CurrentPlot == NULL, "Mismatched BeginPlot()/EndPlot()!");
- IM_ASSERT_USER_ERROR(!(ImHasFlag(x_flags, ImPlotAxisFlags_Time) && ImHasFlag(x_flags, ImPlotAxisFlags_LogScale)), "ImPlotAxisFlags_Time and ImPlotAxisFlags_LogScale cannot be enabled at the same time!");
- IM_ASSERT_USER_ERROR(!ImHasFlag(y1_flags, ImPlotAxisFlags_Time), "Y axes cannot display time formatted labels!");
-
- // FRONT MATTER -----------------------------------------------------------
-
- ImGuiContext &G = *GImGui;
- ImGuiWindow * Window = G.CurrentWindow;
- if (Window->SkipItems) {
- Reset(GImPlot);
- return false;
- }
-
- const ImGuiID ID = Window->GetID(title);
- const ImGuiStyle &Style = G.Style;
- const ImGuiIO & IO = ImGui::GetIO();
-
- bool just_created = gp.Plots.GetByKey(ID) == NULL;
- gp.CurrentPlot = gp.Plots.GetOrAddByKey(ID);
- gp.CurrentPlot->ID = ID;
- ImPlotPlot &plot = *gp.CurrentPlot;
-
- plot.CurrentYAxis = 0;
+static const float MOUSE_CURSOR_DRAG_THRESHOLD = 5.0f;
+static const float BOX_SELECT_DRAG_THRESHOLD = 4.0f;
- if (just_created) {
- plot.Flags = flags;
- plot.XAxis.Flags = x_flags;
- plot.YAxis[0].Flags = y1_flags;
- plot.YAxis[1].Flags = y2_flags;
- plot.YAxis[2].Flags = y3_flags;
- }
- else {
- // TODO: Check which individual flags changed, and only reset those!
- // There's probably an easy bit mask trick I'm not aware of.
- if (flags != plot.PreviousFlags)
- plot.Flags = flags;
- if (x_flags != plot.XAxis.PreviousFlags)
- plot.XAxis.Flags = x_flags;
- if (y1_flags != plot.YAxis[0].PreviousFlags)
- plot.YAxis[0].Flags = y1_flags;
- if (y2_flags != plot.YAxis[1].PreviousFlags)
- plot.YAxis[1].Flags = y2_flags;
- if (y3_flags != plot.YAxis[2].PreviousFlags)
- plot.YAxis[2].Flags = y3_flags;
- }
+bool UpdateInput(ImPlotPlot& plot) {
- plot.PreviousFlags = flags;
- plot.XAxis.PreviousFlags = x_flags;
- plot.YAxis[0].PreviousFlags = y1_flags;
- plot.YAxis[1].PreviousFlags = y2_flags;
- plot.YAxis[2].PreviousFlags = y3_flags;
-
- // capture scroll with a child region
- if (!ImHasFlag(plot.Flags, ImPlotFlags_NoChild)) {
- ImGui::BeginChild(title, ImVec2(size.x == 0 ? gp.Style.PlotDefaultSize.x : size.x, size.y == 0 ? gp.Style.PlotDefaultSize.y : size.y), false, ImGuiWindowFlags_NoScrollbar);
- Window = ImGui::GetCurrentWindow();
- Window->ScrollMax.y = 1.0f;
- gp.ChildWindowMade = true;
- }
- else {
- gp.ChildWindowMade = false;
- }
-
- ImDrawList &DrawList = *Window->DrawList;
-
- // NextPlotData -----------------------------------------------------------
-
- // linked axes
- plot.XAxis.LinkedMin = gp.NextPlotData.LinkedXmin;
- plot.XAxis.LinkedMax = gp.NextPlotData.LinkedXmax;
- PullLinkedAxis(plot.XAxis);
- for (int i = 0; i < IMPLOT_Y_AXES; ++i) {
- plot.YAxis[i].LinkedMin = gp.NextPlotData.LinkedYmin[i];
- plot.YAxis[i].LinkedMax = gp.NextPlotData.LinkedYmax[i];
- PullLinkedAxis(plot.YAxis[i]);
- }
-
- if (gp.NextPlotData.HasXRange) {
- if (!plot.Initialized || gp.NextPlotData.XRangeCond == ImGuiCond_Always)
- plot.XAxis.SetRange(gp.NextPlotData.XRange);
- }
-
- for (int i = 0; i < IMPLOT_Y_AXES; i++) {
- if (gp.NextPlotData.HasYRange[i]) {
- if (!plot.Initialized || gp.NextPlotData.YRangeCond[i] == ImGuiCond_Always)
- plot.YAxis[i].SetRange(gp.NextPlotData.YRange[i]);
- }
- }
-
- // Initialization ------------------------------------------------------------
-
- if (!plot.Initialized) {
- if (!ImHasFlag(plot.XAxis.Flags,ImPlotAxisFlags_NoInitialFit) && !gp.NextPlotData.HasXRange && !gp.NextPlotData.LinkedXmin && !gp.NextPlotData.LinkedXmax)
- gp.FitThisFrame = gp.FitX = true;
- for (int i = 0; i < IMPLOT_Y_AXES; ++i) {
- if (!ImHasFlag(plot.YAxis[i].Flags,ImPlotAxisFlags_NoInitialFit) && !gp.NextPlotData.HasYRange[i] && !gp.NextPlotData.LinkedYmin[i] && !gp.NextPlotData.LinkedYmax[i])
- gp.FitThisFrame = gp.FitY[i] = true;
- }
- }
-
- // AXIS STATES ------------------------------------------------------------
- plot.XAxis.HasRange = gp.NextPlotData.HasXRange; plot.XAxis.RangeCond = gp.NextPlotData.XRangeCond; plot.XAxis.Present = true;
- plot.YAxis[0].HasRange = gp.NextPlotData.HasYRange[0]; plot.YAxis[0].RangeCond = gp.NextPlotData.YRangeCond[0]; plot.YAxis[0].Present = true;
- plot.YAxis[1].HasRange = gp.NextPlotData.HasYRange[1]; plot.YAxis[1].RangeCond = gp.NextPlotData.YRangeCond[1]; plot.YAxis[1].Present = ImHasFlag(plot.Flags, ImPlotFlags_YAxis2);
- plot.YAxis[2].HasRange = gp.NextPlotData.HasYRange[2]; plot.YAxis[2].RangeCond = gp.NextPlotData.YRangeCond[2]; plot.YAxis[2].Present = ImHasFlag(plot.Flags, ImPlotFlags_YAxis3);
-
- for (int i = 0; i < IMPLOT_Y_AXES; ++i) {
- if (!ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_LogScale) && !ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_LogScale))
- gp.Scales[i] = ImPlotScale_LinLin;
- else if (ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_LogScale) && !ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_LogScale))
- gp.Scales[i] = ImPlotScale_LogLin;
- else if (!ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_LogScale) && ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_LogScale))
- gp.Scales[i] = ImPlotScale_LinLog;
- else if (ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_LogScale) && ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_LogScale))
- gp.Scales[i] = ImPlotScale_LogLog;
- }
-
- // constraints
- plot.XAxis.Constrain();
- for (int i = 0; i < IMPLOT_Y_AXES; ++i)
- plot.YAxis[i].Constrain();
-
- // constrain equal axes for primary x and y if not approximately equal
- // constrains x to y since x pixel size depends on y labels width, and causes feedback loops in opposite case
- if (ImHasFlag(plot.Flags, ImPlotFlags_Equal)) {
- double xar = plot.XAxis.GetAspect();
- double yar = plot.YAxis[0].GetAspect();
- if (!ImAlmostEqual(xar,yar) && !plot.YAxis[0].IsInputLocked())
- plot.XAxis.SetAspect(yar);
- }
+ bool changed = false;
- // AXIS COLORS -----------------------------------------------------------------
+ ImPlotContext& gp = *GImPlot;
+ ImGuiIO& IO = ImGui::GetIO();
- UpdateAxisColors(ImPlotCol_XAxis, &plot.XAxis);
- UpdateAxisColors(ImPlotCol_YAxis, &plot.YAxis[0]);
- UpdateAxisColors(ImPlotCol_YAxis2, &plot.YAxis[1]);
- UpdateAxisColors(ImPlotCol_YAxis3, &plot.YAxis[2]);
+ // BUTTON STATE -----------------------------------------------------------
- // BB, PADDING, HOVER -----------------------------------------------------------
+ const ImGuiButtonFlags plot_button_flags = ImGuiButtonFlags_AllowItemOverlap
+ | ImGuiButtonFlags_PressedOnClick
+ | ImGuiButtonFlags_PressedOnDoubleClick
+ | ImGuiButtonFlags_MouseButtonLeft
+ | ImGuiButtonFlags_MouseButtonRight
+ | ImGuiButtonFlags_MouseButtonMiddle;
+ const ImGuiButtonFlags axis_button_flags = ImGuiButtonFlags_FlattenChildren
+ | plot_button_flags;
- // frame
- ImVec2 frame_size = ImGui::CalcItemSize(size, gp.Style.PlotDefaultSize.x, gp.Style.PlotDefaultSize.y);
- 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;
- plot.FrameRect = ImRect(Window->DC.CursorPos, Window->DC.CursorPos + frame_size);
- ImGui::ItemSize(plot.FrameRect);
- if (!ImGui::ItemAdd(plot.FrameRect, ID, &plot.FrameRect)) {
- Reset(GImPlot);
- return false;
- }
- plot.FrameHovered = ImGui::ItemHoverable(plot.FrameRect, ID);
- if (G.HoveredIdPreviousFrame != 0 && G.HoveredIdPreviousFrame != ID)
- plot.FrameHovered = false;
+ const bool plot_clicked = ImGui::ButtonBehavior(plot.PlotRect,plot.ID,&plot.Hovered,&plot.Held,plot_button_flags);
ImGui::SetItemAllowOverlap();
- ImGui::RenderFrame(plot.FrameRect.Min, plot.FrameRect.Max, GetStyleColorU32(ImPlotCol_FrameBg), true, Style.FrameRounding);
-
- // canvas/axes bb
- plot.CanvasRect = ImRect(plot.FrameRect.Min + gp.Style.PlotPadding, plot.FrameRect.Max - gp.Style.PlotPadding);
- plot.AxesRect = plot.FrameRect;
- // outside legend adjustments
- if (!ImHasFlag(plot.Flags, ImPlotFlags_NoLegend) && plot.GetLegendCount() > 0 && plot.LegendOutside) {
- const ImVec2 legend_size = CalcLegendSize(plot, gp.Style.LegendInnerPadding, gp.Style.LegendSpacing, plot.LegendOrientation);
- const bool west = ImHasFlag(plot.LegendLocation, ImPlotLocation_West) && !ImHasFlag(plot.LegendLocation, ImPlotLocation_East);
- const bool east = ImHasFlag(plot.LegendLocation, ImPlotLocation_East) && !ImHasFlag(plot.LegendLocation, ImPlotLocation_West);
- const bool north = ImHasFlag(plot.LegendLocation, ImPlotLocation_North) && !ImHasFlag(plot.LegendLocation, ImPlotLocation_South);
- const bool south = ImHasFlag(plot.LegendLocation, ImPlotLocation_South) && !ImHasFlag(plot.LegendLocation, ImPlotLocation_North);
- const bool horz = plot.LegendOrientation == ImPlotOrientation_Horizontal;
- if ((west && !horz) || (west && horz && !north && !south)) {
- plot.CanvasRect.Min.x += (legend_size.x + gp.Style.LegendPadding.x);
- plot.AxesRect.Min.x += (legend_size.x + gp.Style.PlotPadding.x);
+ if (plot_clicked) {
+ if (!ImHasFlag(plot.Flags, ImPlotFlags_NoBoxSelect) && IO.MouseClicked[gp.InputMap.Select] && ImHasFlag(IO.KeyMods, gp.InputMap.SelectMod)) {
+ plot.Selecting = true;
+ plot.SelectStart = IO.MousePos;
+ plot.SelectRect = ImRect(0,0,0,0);
}
- if ((east && !horz) || (east && horz && !north && !south)) {
- plot.CanvasRect.Max.x -= (legend_size.x + gp.Style.LegendPadding.x);
- plot.AxesRect.Max.x -= (legend_size.x + gp.Style.PlotPadding.x);
- }
- if ((north && horz) || (north && !horz && !west && !east)) {
- plot.CanvasRect.Min.y += (legend_size.y + gp.Style.LegendPadding.y);
- plot.AxesRect.Min.y += (legend_size.y + gp.Style.PlotPadding.y);
- }
- if ((south && horz) || (south && !horz && !west && !east)) {
- plot.CanvasRect.Max.y -= (legend_size.y + gp.Style.LegendPadding.y);
- plot.AxesRect.Max.y -= (legend_size.y + gp.Style.PlotPadding.y);
+ if (IO.MouseDoubleClicked[gp.InputMap.Fit]) {
+ plot.FitThisFrame = true;
+ for (int i = 0; i < ImAxis_COUNT; ++i)
+ plot.Axes[i].FitThisFrame = true;
}
}
- gp.RenderX = (!ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_NoGridLines) ||
- !ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_NoTickMarks) ||
- !ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_NoTickLabels));
- for (int i = 0; i < IMPLOT_Y_AXES; i++) {
- gp.RenderY[i] = plot.YAxis[i].Present &&
- (!ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_NoGridLines) ||
- !ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_NoTickMarks) ||
- !ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_NoTickLabels));
- }
-
- // plot bb
+ const bool can_pan = IO.MouseDown[gp.InputMap.Pan] && ImHasFlag(IO.KeyMods, gp.InputMap.PanMod);
- // (1) calc top/bot padding and plot height
- ImVec2 title_size(0.0f, 0.0f);
- const float txt_height = ImGui::GetTextLineHeight();
- if (!ImHasFlag(plot.Flags, ImPlotFlags_NoTitle)){
- title_size = ImGui::CalcTextSize(title, NULL, true);
- }
+ plot.Held = plot.Held && can_pan;
- const bool show_x_label = x_label && !ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_NoLabel);
+ bool x_click[IMPLOT_NUM_X_AXES] = {false};
+ bool x_held[IMPLOT_NUM_X_AXES] = {false};
+ bool x_hov[IMPLOT_NUM_X_AXES] = {false};
- const float pad_top = title_size.x > 0.0f ? txt_height + gp.Style.LabelPadding.y : 0;
- const float pad_bot = (plot.XAxis.IsLabeled() ? ImMax(txt_height, gp.XTicks.MaxHeight) + gp.Style.LabelPadding.y + (plot.XAxis.IsTime() ? txt_height + gp.Style.LabelPadding.y : 0) : 0)
- + (show_x_label ? txt_height + gp.Style.LabelPadding.y : 0);
+ bool y_click[IMPLOT_NUM_Y_AXES] = {false};
+ bool y_held[IMPLOT_NUM_Y_AXES] = {false};
+ bool y_hov[IMPLOT_NUM_Y_AXES] = {false};
- const float plot_height = plot.CanvasRect.GetHeight() - pad_top - pad_bot;
-
- // (2) get y tick labels (needed for left/right pad)
- for (int i = 0; i < IMPLOT_Y_AXES; i++) {
- if (gp.RenderY[i] && gp.NextPlotData.ShowDefaultTicksY[i]) {
- if (ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_LogScale))
- AddTicksLogarithmic(plot.YAxis[i].Range, plot_height, ImPlotOrientation_Vertical, gp.YTicks[i], GetFormatY(i));
- else
- AddTicksDefault(plot.YAxis[i].Range, plot_height, ImPlotOrientation_Vertical, gp.YTicks[i], GetFormatY(i));
+ for (int i = 0; i < IMPLOT_NUM_X_AXES; ++i) {
+ ImPlotAxis& xax = plot.XAxis(i);
+ if (xax.Enabled) {
+ ImGui::KeepAliveID(xax.ID);
+ x_click[i] = ImGui::ButtonBehavior(xax.HoverRect,xax.ID,&xax.Hovered,&xax.Held,axis_button_flags);
+ if (x_click[i] && IO.MouseDoubleClicked[gp.InputMap.Fit])
+ plot.FitThisFrame = xax.FitThisFrame = true;
+ xax.Held = xax.Held && can_pan;
+ x_hov[i] = xax.Hovered || plot.Hovered;
+ x_held[i] = xax.Held || plot.Held;
}
}
- // (3) calc left/right pad
- const bool show_y1_label = y1_label && !ImHasFlag(plot.YAxis[0].Flags, ImPlotAxisFlags_NoLabel);
- const bool show_y2_label = y2_label && !ImHasFlag(plot.YAxis[1].Flags, ImPlotAxisFlags_NoLabel);
- const bool show_y3_label = y3_label && !ImHasFlag(plot.YAxis[2].Flags, ImPlotAxisFlags_NoLabel);
-
- const float pad_left = (show_y1_label ? txt_height + gp.Style.LabelPadding.x : 0)
- + (plot.YAxis[0].IsLabeled() ? gp.YTicks[0].MaxWidth + gp.Style.LabelPadding.x : 0);
- const float pad_right = ((plot.YAxis[1].Present && plot.YAxis[1].IsLabeled()) ? gp.YTicks[1].MaxWidth + gp.Style.LabelPadding.x : 0)
- + ((plot.YAxis[1].Present && show_y2_label) ? txt_height + gp.Style.LabelPadding.x : 0)
- + ((plot.YAxis[1].Present && plot.YAxis[2].Present) ? gp.Style.LabelPadding.x + gp.Style.MinorTickLen.y : 0)
- + ((plot.YAxis[2].Present && plot.YAxis[2].IsLabeled()) ? gp.YTicks[2].MaxWidth + gp.Style.LabelPadding.x : 0)
- + ((plot.YAxis[2].Present && show_y3_label) ? txt_height + gp.Style.LabelPadding.x : 0);
-
- const float plot_width = plot.CanvasRect.GetWidth() - pad_left - pad_right;
-
- // (4) get x ticks
- if (gp.RenderX && gp.NextPlotData.ShowDefaultTicksX) {
- if (plot.XAxis.IsTime())
- AddTicksTime(plot.XAxis.Range, plot_width, gp.XTicks);
- else if (ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_LogScale))
- AddTicksLogarithmic(plot.XAxis.Range, plot_width, ImPlotOrientation_Horizontal, gp.XTicks, GetFormatX());
- else
- AddTicksDefault(plot.XAxis.Range, plot_width, ImPlotOrientation_Horizontal, gp.XTicks, GetFormatX());
+ for (int i = 0; i < IMPLOT_NUM_Y_AXES; ++i) {
+ ImPlotAxis& yax = plot.YAxis(i);
+ if (yax.Enabled) {
+ ImGui::KeepAliveID(yax.ID);
+ y_click[i] = ImGui::ButtonBehavior(yax.HoverRect,yax.ID,&yax.Hovered,&yax.Held,axis_button_flags);
+ if (y_click[i] && IO.MouseDoubleClicked[gp.InputMap.Fit])
+ plot.FitThisFrame = yax.FitThisFrame = true;
+ yax.Held = yax.Held && can_pan;
+ y_hov[i] = yax.Hovered || plot.Hovered;
+ y_held[i] = yax.Held || plot.Held;
+ }
}
- // (5) calc plot bb
- plot.PlotRect = ImRect(plot.CanvasRect.Min + ImVec2(pad_left, pad_top), plot.CanvasRect.Max - ImVec2(pad_right, pad_bot));
- plot.PlotHovered = plot.FrameHovered && plot.PlotRect.Contains(IO.MousePos);
-
- // x axis region bb and hover
- plot.XAxis.HoverRect = ImRect(plot.PlotRect.GetBL(), ImVec2(plot.PlotRect.Max.x, plot.AxesRect.Max.y));
- plot.XAxis.ExtHovered = plot.XAxis.HoverRect.Contains(IO.MousePos);
- plot.XAxis.AllHovered = plot.XAxis.ExtHovered || plot.PlotHovered;
-
- // axis label reference
- gp.YAxisReference[0] = plot.PlotRect.Min.x;
- gp.YAxisReference[1] = plot.PlotRect.Max.x;
- gp.YAxisReference[2] = !plot.YAxis[1].Present ? plot.PlotRect.Max.x : gp.YAxisReference[1]
- + (plot.YAxis[1].IsLabeled() ? gp.Style.LabelPadding.x + gp.YTicks[1].MaxWidth : 0)
- + (show_y2_label ? txt_height + gp.Style.LabelPadding.x : 0)
- + gp.Style.LabelPadding.x + gp.Style.MinorTickLen.y;
+ // cancel due to DND activity
+ if (GImGui->DragDropActive || (IO.KeyMods == gp.InputMap.OverrideMod && gp.InputMap.OverrideMod != 0))
+ return false;
- // y axis regions bb and hover
- plot.YAxis[0].HoverRect = ImRect(ImVec2(plot.AxesRect.Min.x, plot.PlotRect.Min.y), ImVec2(plot.PlotRect.Min.x, plot.PlotRect.Max.y));
- plot.YAxis[1].HoverRect = plot.YAxis[2].Present
- ? ImRect(plot.PlotRect.GetTR(), ImVec2(gp.YAxisReference[2], plot.PlotRect.Max.y))
- : ImRect(plot.PlotRect.GetTR(), ImVec2(plot.AxesRect.Max.x, plot.PlotRect.Max.y));
+ // STATE -------------------------------------------------------------------
- plot.YAxis[2].HoverRect = ImRect(ImVec2(gp.YAxisReference[2], plot.PlotRect.Min.y), ImVec2(plot.AxesRect.Max.x, plot.PlotRect.Max.y));
+ const bool axis_equal = ImHasFlag(plot.Flags, ImPlotFlags_Equal);
- for (int i = 0; i < IMPLOT_Y_AXES; ++i) {
- plot.YAxis[i].ExtHovered = plot.YAxis[i].Present && plot.YAxis[i].HoverRect.Contains(IO.MousePos);
- plot.YAxis[i].AllHovered = plot.YAxis[i].ExtHovered || plot.PlotHovered;
- }
+ const bool any_x_hov = plot.Hovered || AnyAxesHovered(&plot.Axes[ImAxis_X1], IMPLOT_NUM_X_AXES);
+ const bool any_x_held = plot.Held || AnyAxesHeld(&plot.Axes[ImAxis_X1], IMPLOT_NUM_X_AXES);
+ const bool any_y_hov = plot.Hovered || AnyAxesHovered(&plot.Axes[ImAxis_Y1], IMPLOT_NUM_Y_AXES);
+ const bool any_y_held = plot.Held || AnyAxesHeld(&plot.Axes[ImAxis_Y1], IMPLOT_NUM_Y_AXES);
+ const bool any_hov = any_x_hov || any_y_hov;
+ const bool any_held = any_x_held || any_y_held;
- const bool any_hov_y_axis_region = plot.YAxis[0].AllHovered || plot.YAxis[1].AllHovered || plot.YAxis[2].AllHovered;
+ const ImVec2 select_drag = ImGui::GetMouseDragDelta(gp.InputMap.Select);
+ const ImVec2 pan_drag = ImGui::GetMouseDragDelta(gp.InputMap.Pan);
+ const float select_drag_sq = ImLengthSqr(select_drag);
+ const float pan_drag_sq = ImLengthSqr(pan_drag);
+ const bool selecting = plot.Selecting && select_drag_sq > MOUSE_CURSOR_DRAG_THRESHOLD;
+ const bool panning = any_held && pan_drag_sq > MOUSE_CURSOR_DRAG_THRESHOLD;
- bool hov_query = false;
- if (plot.PlotHovered && plot.Queried && !plot.Querying) {
- ImRect bb_query = plot.QueryRect;
- bb_query.Min += plot.PlotRect.Min;
- bb_query.Max += plot.PlotRect.Min;
- hov_query = bb_query.Contains(IO.MousePos);
- }
+ // CONTEXT MENU -----------------------------------------------------------
- // AXIS ASPECT RATIOS
- plot.XAxis.Pixels = plot.PlotRect.GetWidth();
- for (int i = 0; i < IMPLOT_Y_AXES; ++i)
- plot.YAxis[i].Pixels = plot.PlotRect.GetHeight();
+ if (IO.MouseReleased[gp.InputMap.Menu] && !plot.ContextLocked)
+ gp.OpenContextThisFrame = true;
- // QUERY DRAG -------------------------------------------------------------
- if (plot.DraggingQuery && (IO.MouseReleased[gp.InputMap.PanButton] || !IO.MouseDown[gp.InputMap.PanButton])) {
- plot.DraggingQuery = false;
- }
- if (plot.DraggingQuery) {
- ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeAll);
- plot.QueryRect.Min += IO.MouseDelta;
- plot.QueryRect.Max += IO.MouseDelta;
- }
- if (plot.PlotHovered && hov_query && !plot.DraggingQuery && !plot.Selecting && !plot.LegendHovered) {
- ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeAll);
- 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) {
- plot.DraggingQuery = true;
- }
- }
+ if (selecting || panning)
+ plot.ContextLocked = true;
+ else if (!(IO.MouseDown[gp.InputMap.Menu] || IO.MouseReleased[gp.InputMap.Menu]))
+ plot.ContextLocked = false;
// DRAG INPUT -------------------------------------------------------------
- const bool axis_equal = ImHasFlag(plot.Flags, ImPlotFlags_Equal);
-
- // end drags
- if (plot.XAxis.Dragging && (IO.MouseReleased[gp.InputMap.PanButton] || !IO.MouseDown[gp.InputMap.PanButton])) {
- plot.XAxis.Dragging = false;
- G.IO.MouseDragMaxDistanceSqr[0] = 0;
- }
- 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;
- G.IO.MouseDragMaxDistanceSqr[0] = 0;
- }
- }
- const bool any_y_dragging = plot.YAxis[0].Dragging || plot.YAxis[1].Dragging || plot.YAxis[2].Dragging;
- bool drag_in_progress = plot.XAxis.Dragging || any_y_dragging;
- // do drag
- if (drag_in_progress) {
- UpdateTransformCache();
- bool equal_dragged = false;
- // special case for axis equal and both x and y0 hovered
- if (axis_equal && !plot.XAxis.IsInputLocked() && plot.XAxis.Dragging && !plot.YAxis[0].IsInputLocked() && plot.YAxis[0].Dragging) {
- ImPlotPoint plot_tl = PixelsToPlot(plot.PlotRect.Min - IO.MouseDelta, 0);
- ImPlotPoint plot_br = PixelsToPlot(plot.PlotRect.Max - IO.MouseDelta, 0);
- plot.XAxis.SetMin(plot.XAxis.IsInverted() ? plot_br.x : plot_tl.x);
- plot.XAxis.SetMax(plot.XAxis.IsInverted() ? plot_tl.x : plot_br.x);
- plot.YAxis[0].SetMin(plot.YAxis[0].IsInverted() ? plot_tl.y : plot_br.y);
- plot.YAxis[0].SetMax(plot.YAxis[0].IsInverted() ? plot_br.y : plot_tl.y);
- double xar = plot.XAxis.GetAspect();
- double yar = plot.YAxis[0].GetAspect();
- if (!ImAlmostEqual(xar,yar) && !plot.YAxis[0].IsInputLocked())
- plot.XAxis.SetAspect(yar);
- equal_dragged = true;
- }
- if (!plot.XAxis.IsInputLocked() && plot.XAxis.Dragging && !equal_dragged) {
- ImPlotPoint plot_tl = PixelsToPlot(plot.PlotRect.Min - IO.MouseDelta, 0);
- ImPlotPoint plot_br = PixelsToPlot(plot.PlotRect.Max - IO.MouseDelta, 0);
- plot.XAxis.SetMin(plot.XAxis.IsInverted() ? plot_br.x : plot_tl.x);
- plot.XAxis.SetMax(plot.XAxis.IsInverted() ? plot_tl.x : plot_br.x);
- if (axis_equal)
- plot.YAxis[0].SetAspect(plot.XAxis.GetAspect());
- }
- for (int i = 0; i < IMPLOT_Y_AXES; i++) {
- if (!plot.YAxis[i].IsInputLocked() && plot.YAxis[i].Dragging && !(i == 0 && equal_dragged)) {
- ImPlotPoint plot_tl = PixelsToPlot(plot.PlotRect.Min - IO.MouseDelta, i);
- ImPlotPoint plot_br = PixelsToPlot(plot.PlotRect.Max - IO.MouseDelta, i);
- plot.YAxis[i].SetMin(plot.YAxis[i].IsInverted() ? plot_tl.y : plot_br.y);
- plot.YAxis[i].SetMax(plot.YAxis[i].IsInverted() ? plot_br.y : plot_tl.y);
- if (i == 0 && axis_equal)
- plot.XAxis.SetAspect(plot.YAxis[0].GetAspect());
+ if (any_held && !plot.Selecting) {
+ int drag_direction = 0;
+ for (int i = 0; i < IMPLOT_NUM_X_AXES; i++) {
+ ImPlotAxis& x_axis = plot.XAxis(i);
+ if (x_held[i] && !x_axis.IsInputLocked()) {
+ drag_direction |= (1 << 1);
+ const double plot_l = x_axis.PixelsToPlot(plot.PlotRect.Min.x - IO.MouseDelta.x);
+ const double plot_r = x_axis.PixelsToPlot(plot.PlotRect.Max.x - IO.MouseDelta.x);
+ x_axis.SetMin(x_axis.IsInverted() ? plot_r : plot_l);
+ x_axis.SetMax(x_axis.IsInverted() ? plot_l : plot_r);
+ if (axis_equal && x_axis.OrthoAxis != NULL)
+ x_axis.OrthoAxis->SetAspect(x_axis.GetAspect());
+ changed = true;
}
}
- // Set the mouse cursor based on which axes are moving.
- int direction = 0;
- if (!plot.XAxis.IsInputLocked() && plot.XAxis.Dragging) {
- direction |= (1 << 1);
- }
- for (int i = 0; i < IMPLOT_Y_AXES; i++) {
- if (!plot.YAxis[i].Present) { continue; }
- if (!plot.YAxis[i].IsInputLocked() && plot.YAxis[i].Dragging) {
- direction |= (1 << 2);
- break;
+ for (int i = 0; i < IMPLOT_NUM_Y_AXES; i++) {
+ ImPlotAxis& y_axis = plot.YAxis(i);
+ if (y_held[i] && !y_axis.IsInputLocked()) {
+ drag_direction |= (1 << 2);
+ const double plot_t = y_axis.PixelsToPlot(plot.PlotRect.Min.y - IO.MouseDelta.y);
+ const double plot_b = y_axis.PixelsToPlot(plot.PlotRect.Max.y - IO.MouseDelta.y);
+ y_axis.SetMin(y_axis.IsInverted() ? plot_t : plot_b);
+ y_axis.SetMax(y_axis.IsInverted() ? plot_b : plot_t);
+ if (axis_equal && y_axis.OrthoAxis != NULL)
+ y_axis.OrthoAxis->SetAspect(y_axis.GetAspect());
+ changed = true;
}
}
- if (IO.MouseDragMaxDistanceSqr[0] > 5) {
- 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);
- }
- }
- // start drag
- if (!drag_in_progress && plot.FrameHovered && IO.MouseClicked[gp.InputMap.PanButton] && ImHasFlag(IO.KeyMods, gp.InputMap.PanMod) && !plot.Selecting && !plot.LegendHovered && !hov_query && !plot.DraggingQuery) {
- if (plot.XAxis.AllHovered) {
- plot.XAxis.Dragging = true;
- }
- for (int i = 0; i < IMPLOT_Y_AXES; i++) {
- if (plot.YAxis[i].AllHovered) {
- plot.YAxis[i].Dragging = true;
+ if (IO.MouseDragMaxDistanceSqr[gp.InputMap.Pan] > MOUSE_CURSOR_DRAG_THRESHOLD) {
+ switch (drag_direction) {
+ case 0 : ImGui::SetMouseCursor(ImGuiMouseCursor_NotAllowed); break;
+ case (1 << 1) : ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeEW); break;
+ case (1 << 2) : ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeNS); break;
+ default : ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeAll); break;
}
}
}
// SCROLL INPUT -----------------------------------------------------------
- if (plot.FrameHovered && (plot.XAxis.AllHovered || any_hov_y_axis_region) && IO.MouseWheel != 0) {
- UpdateTransformCache();
- float zoom_rate = IMPLOT_ZOOM_RATE;
+ if (any_hov && IO.MouseWheel != 0 && ImHasFlag(IO.KeyMods, gp.InputMap.ZoomMod)) {
+
+ float zoom_rate = gp.InputMap.ZoomRate;
if (IO.MouseWheel > 0)
zoom_rate = (-zoom_rate) / (1.0f + (2.0f * zoom_rate));
+ ImVec2 rect_size = plot.PlotRect.GetSize();
float tx = ImRemap(IO.MousePos.x, plot.PlotRect.Min.x, plot.PlotRect.Max.x, 0.0f, 1.0f);
float ty = ImRemap(IO.MousePos.y, plot.PlotRect.Min.y, plot.PlotRect.Max.y, 0.0f, 1.0f);
- bool equal_zoomed = false;
- // special case for axis equal and both x and y0 hovered
- if (axis_equal && plot.XAxis.AllHovered && !plot.XAxis.IsInputLocked() && plot.YAxis[0].AllHovered && !plot.YAxis[0].IsInputLocked()) {
- const ImPlotPoint& plot_tl = PixelsToPlot(plot.PlotRect.Min - plot.PlotRect.GetSize() * ImVec2(tx * zoom_rate, ty * zoom_rate), 0);
- const ImPlotPoint& plot_br = PixelsToPlot(plot.PlotRect.Max + plot.PlotRect.GetSize() * ImVec2((1 - tx) * zoom_rate, (1 - ty) * zoom_rate), 0);
- plot.XAxis.SetMin(plot.XAxis.IsInverted() ? plot_br.x : plot_tl.x);
- plot.XAxis.SetMax(plot.XAxis.IsInverted() ? plot_tl.x : plot_br.x);
- plot.YAxis[0].SetMin(plot.YAxis[0].IsInverted() ? plot_tl.y : plot_br.y);
- plot.YAxis[0].SetMax(plot.YAxis[0].IsInverted() ? plot_br.y : plot_tl.y);
- double xar = plot.XAxis.GetAspect();
- double yar = plot.YAxis[0].GetAspect();
- if (!ImAlmostEqual(xar,yar) && !plot.YAxis[0].IsInputLocked())
- plot.XAxis.SetAspect(yar);
- equal_zoomed = true;
- }
- if (plot.XAxis.AllHovered && !plot.XAxis.IsInputLocked() && !equal_zoomed) {
- const ImPlotPoint& plot_tl = PixelsToPlot(plot.PlotRect.Min - plot.PlotRect.GetSize() * ImVec2(tx * zoom_rate, ty * zoom_rate), 0);
- const ImPlotPoint& plot_br = PixelsToPlot(plot.PlotRect.Max + plot.PlotRect.GetSize() * ImVec2((1 - tx) * zoom_rate, (1 - ty) * zoom_rate), 0);
- plot.XAxis.SetMin(plot.XAxis.IsInverted() ? plot_br.x : plot_tl.x);
- plot.XAxis.SetMax(plot.XAxis.IsInverted() ? plot_tl.x : plot_br.x);
- if (axis_equal)
- plot.YAxis[0].SetAspect(plot.XAxis.GetAspect());
+
+ for (int i = 0; i < IMPLOT_NUM_X_AXES; i++) {
+ ImPlotAxis& x_axis = plot.XAxis(i);
+ const bool equal_zoom = axis_equal && x_axis.OrthoAxis != NULL;
+ const bool equal_locked = (equal_zoom != false) && x_axis.OrthoAxis->IsInputLocked();
+ if (x_hov[i] && !x_axis.IsInputLocked() && !equal_locked) {
+ float correction = (plot.Hovered && equal_zoom) ? 0.5f : 1.0f;
+ const double plot_l = x_axis.PixelsToPlot(plot.PlotRect.Min.x - rect_size.x * tx * zoom_rate * correction);
+ const double plot_r = x_axis.PixelsToPlot(plot.PlotRect.Max.x + rect_size.x * (1 - tx) * zoom_rate * correction);
+ x_axis.SetMin(x_axis.IsInverted() ? plot_r : plot_l);
+ x_axis.SetMax(x_axis.IsInverted() ? plot_l : plot_r);
+ if (axis_equal && x_axis.OrthoAxis != NULL)
+ x_axis.OrthoAxis->SetAspect(x_axis.GetAspect());
+ changed = true;
+ }
}
- for (int i = 0; i < IMPLOT_Y_AXES; i++) {
- if (plot.YAxis[i].AllHovered && !plot.YAxis[i].IsInputLocked() && !(i == 0 && equal_zoomed)) {
- const ImPlotPoint& plot_tl = PixelsToPlot(plot.PlotRect.Min - plot.PlotRect.GetSize() * ImVec2(tx * zoom_rate, ty * zoom_rate), i);
- const ImPlotPoint& plot_br = PixelsToPlot(plot.PlotRect.Max + plot.PlotRect.GetSize() * ImVec2((1 - tx) * zoom_rate, (1 - ty) * zoom_rate), i);
- plot.YAxis[i].SetMin(plot.YAxis[i].IsInverted() ? plot_tl.y : plot_br.y);
- plot.YAxis[i].SetMax(plot.YAxis[i].IsInverted() ? plot_br.y : plot_tl.y);
- if (i == 0 && axis_equal)
- plot.XAxis.SetAspect(plot.YAxis[0].GetAspect());
+ for (int i = 0; i < IMPLOT_NUM_Y_AXES; i++) {
+ ImPlotAxis& y_axis = plot.YAxis(i);
+ const bool equal_zoom = axis_equal && y_axis.OrthoAxis != NULL;
+ const bool equal_locked = equal_zoom && y_axis.OrthoAxis->IsInputLocked();
+ if (y_hov[i] && !y_axis.IsInputLocked() && !equal_locked) {
+ float correction = (plot.Hovered && equal_zoom) ? 0.5f : 1.0f;
+ const double plot_t = y_axis.PixelsToPlot(plot.PlotRect.Min.y - rect_size.y * ty * zoom_rate * correction);
+ const double plot_b = y_axis.PixelsToPlot(plot.PlotRect.Max.y + rect_size.y * (1 - ty) * zoom_rate * correction);
+ y_axis.SetMin(y_axis.IsInverted() ? plot_t : plot_b);
+ y_axis.SetMax(y_axis.IsInverted() ? plot_b : plot_t);
+ if (axis_equal && y_axis.OrthoAxis != NULL)
+ y_axis.OrthoAxis->SetAspect(y_axis.GetAspect());
+ changed = true;
}
}
}
- // BOX-SELECTION AND QUERY ------------------------------------------------
+ // BOX-SELECTION ----------------------------------------------------------
- // begin selection
- if (!ImHasFlag(plot.Flags, ImPlotFlags_NoBoxSelect) && plot.PlotHovered && IO.MouseClicked[gp.InputMap.BoxSelectButton] && ImHasFlag(IO.KeyMods, gp.InputMap.BoxSelectMod)) {
- plot.Selecting = true;
- plot.SelectStart = IO.MousePos;
- plot.SelectRect = ImRect(0,0,0,0);
- }
- // update selection
if (plot.Selecting) {
- UpdateTransformCache();
const ImVec2 d = plot.SelectStart - IO.MousePos;
- const bool x_can_change = !ImHasFlag(IO.KeyMods,gp.InputMap.HorizontalMod) && ImFabs(d.x) > 2;
- const bool y_can_change = !ImHasFlag(IO.KeyMods,gp.InputMap.VerticalMod) && ImFabs(d.y) > 2;
+ const bool x_can_change = !ImHasFlag(IO.KeyMods,gp.InputMap.SelectHorzMod) && ImFabs(d.x) > 2;
+ const bool y_can_change = !ImHasFlag(IO.KeyMods,gp.InputMap.SelectVertMod) && ImFabs(d.y) > 2;
// confirm
- if (IO.MouseReleased[gp.InputMap.BoxSelectButton] || !IO.MouseDown[gp.InputMap.BoxSelectButton]) {
- if (!plot.XAxis.IsInputLocked() && x_can_change) {
- ImPlotPoint p1 = PixelsToPlot(plot.SelectStart);
- ImPlotPoint p2 = PixelsToPlot(IO.MousePos);
- plot.XAxis.SetMin(ImMin(p1.x, p2.x));
- plot.XAxis.SetMax(ImMax(p1.x, p2.x));
+ if (IO.MouseReleased[gp.InputMap.Select]) {
+ for (int i = 0; i < IMPLOT_NUM_X_AXES; i++) {
+ ImPlotAxis& x_axis = plot.XAxis(i);
+ if (!x_axis.IsInputLocked() && x_can_change) {
+ const double p1 = x_axis.PixelsToPlot(plot.SelectStart.x);
+ const double p2 = x_axis.PixelsToPlot(IO.MousePos.x);
+ x_axis.SetMin(ImMin(p1, p2));
+ x_axis.SetMax(ImMax(p1, p2));
+ changed = true;
+ }
}
- for (int i = 0; i < IMPLOT_Y_AXES; i++) {
- if (!plot.YAxis[i].IsInputLocked() && y_can_change) {
- ImPlotPoint p1 = PixelsToPlot(plot.SelectStart, i);
- ImPlotPoint p2 = PixelsToPlot(IO.MousePos, i);
- plot.YAxis[i].SetMin(ImMin(p1.y, p2.y));
- plot.YAxis[i].SetMax(ImMax(p1.y, p2.y));
+ for (int i = 0; i < IMPLOT_NUM_Y_AXES; i++) {
+ ImPlotAxis& y_axis = plot.YAxis(i);
+ if (!y_axis.IsInputLocked() && y_can_change) {
+ const double p1 = y_axis.PixelsToPlot(plot.SelectStart.y);
+ const double p2 = y_axis.PixelsToPlot(IO.MousePos.y);
+ y_axis.SetMin(ImMin(p1, p2));
+ y_axis.SetMax(ImMax(p1, p2));
+ changed = true;
}
}
- if (x_can_change || y_can_change || (ImHasFlag(IO.KeyMods,gp.InputMap.HorizontalMod) && ImHasFlag(IO.KeyMods,gp.InputMap.VerticalMod)))
- plot.ContextLocked = gp.InputMap.BoxSelectButton == gp.InputMap.ContextMenuButton;
+ if (x_can_change || y_can_change || (ImHasFlag(IO.KeyMods,gp.InputMap.SelectHorzMod) && ImHasFlag(IO.KeyMods,gp.InputMap.SelectVertMod)))
+ gp.OpenContextThisFrame = false;
plot.Selected = plot.Selecting = false;
}
// cancel
- else if (IO.MouseClicked[gp.InputMap.BoxSelectCancelButton] || IO.MouseDown[gp.InputMap.BoxSelectCancelButton]) {
+ else if (IO.MouseReleased[gp.InputMap.SelectCancel]) {
plot.Selected = plot.Selecting = false;
- plot.ContextLocked = gp.InputMap.BoxSelectButton == gp.InputMap.ContextMenuButton;
+ gp.OpenContextThisFrame = false;
}
- else if (ImLengthSqr(d) > 4) {
+ else if (ImLengthSqr(d) > BOX_SELECT_DRAG_THRESHOLD) {
// bad selection
if (plot.IsInputLocked()) {
ImGui::SetMouseCursor(ImGuiMouseCursor_NotAllowed);
- plot.ContextLocked = gp.InputMap.BoxSelectButton == gp.InputMap.ContextMenuButton;
+ gp.OpenContextThisFrame = false;
plot.Selected = false;
}
else {
// TODO: Handle only min or max locked cases
- plot.SelectRect.Min.x = ImHasFlag(IO.KeyMods, gp.InputMap.HorizontalMod) || plot.XAxis.IsInputLocked() ? plot.PlotRect.Min.x : ImMin(plot.SelectStart.x, IO.MousePos.x);
- plot.SelectRect.Max.x = ImHasFlag(IO.KeyMods, gp.InputMap.HorizontalMod) || plot.XAxis.IsInputLocked() ? plot.PlotRect.Max.x : ImMax(plot.SelectStart.x, IO.MousePos.x);
- plot.SelectRect.Min.y = ImHasFlag(IO.KeyMods, gp.InputMap.VerticalMod) || plot.AllYInputLocked() ? plot.PlotRect.Min.y : ImMin(plot.SelectStart.y, IO.MousePos.y);
- plot.SelectRect.Max.y = ImHasFlag(IO.KeyMods, gp.InputMap.VerticalMod) || plot.AllYInputLocked() ? plot.PlotRect.Max.y : ImMax(plot.SelectStart.y, IO.MousePos.y);
+ const bool full_width = ImHasFlag(IO.KeyMods, gp.InputMap.SelectHorzMod) || AllAxesInputLocked(&plot.Axes[ImAxis_X1], IMPLOT_NUM_X_AXES);
+ const bool full_height = ImHasFlag(IO.KeyMods, gp.InputMap.SelectVertMod) || AllAxesInputLocked(&plot.Axes[ImAxis_Y1], IMPLOT_NUM_Y_AXES);
+ plot.SelectRect.Min.x = full_width ? plot.PlotRect.Min.x : ImMin(plot.SelectStart.x, IO.MousePos.x);
+ plot.SelectRect.Max.x = full_width ? plot.PlotRect.Max.x : ImMax(plot.SelectStart.x, IO.MousePos.x);
+ plot.SelectRect.Min.y = full_height ? plot.PlotRect.Min.y : ImMin(plot.SelectStart.y, IO.MousePos.y);
+ plot.SelectRect.Max.y = full_height ? plot.PlotRect.Max.y : ImMax(plot.SelectStart.y, IO.MousePos.y);
plot.SelectRect.Min -= plot.PlotRect.Min;
plot.SelectRect.Max -= plot.PlotRect.Min;
plot.Selected = true;
@@ -1827,395 +2001,623 @@ bool BeginPlot(const char* title, const char* x_label, const char* y1_label, con
plot.Selected = false;
}
}
+ return changed;
+}
- // begin query
- if (ImHasFlag(plot.Flags, ImPlotFlags_Query) && plot.PlotHovered && IO.MouseClicked[gp.InputMap.QueryButton] && ImHasFlag(IO.KeyMods, gp.InputMap.QueryMod)) {
- plot.Querying = true;
- plot.QueryStart = IO.MousePos;
- plot.QueryRect = ImRect(0,0,0,0);
+//-----------------------------------------------------------------------------
+// Next Plot Data (Legacy)
+//-----------------------------------------------------------------------------
+
+void ApplyNextPlotData(ImAxis idx) {
+ ImPlotContext& gp = *GImPlot;
+ ImPlotPlot& plot = *GImPlot->CurrentPlot;
+ ImPlotAxis& axis = plot.Axes[idx];
+ if (!axis.Enabled)
+ return;
+ double* npd_lmin = gp.NextPlotData.LinkedMin[idx];
+ double* npd_lmax = gp.NextPlotData.LinkedMax[idx];
+ bool npd_rngh = gp.NextPlotData.HasRange[idx];
+ ImPlotCond npd_rngc = gp.NextPlotData.RangeCond[idx];
+ ImPlotRange npd_rngv = gp.NextPlotData.Range[idx];
+ axis.LinkedMin = npd_lmin;
+ axis.LinkedMax = npd_lmax;
+ axis.PullLinks();
+ if (npd_rngh) {
+ if (!plot.Initialized || npd_rngc == ImPlotCond_Always)
+ axis.SetRange(npd_rngv);
}
- // update query
- if (plot.Querying) {
- UpdateTransformCache();
- // confirm
- if (IO.MouseReleased[gp.InputMap.QueryButton] || IO.MouseReleased[gp.InputMap.BoxSelectButton]) {
- plot.Querying = false;
- if (plot.QueryRect.GetWidth() > 2 && plot.QueryRect.GetHeight() > 2) {
- plot.Queried = true;
- plot.ContextLocked = gp.InputMap.BoxSelectButton == gp.InputMap.ContextMenuButton;
- }
- else
- plot.Queried = false;
- }
- else {
- plot.QueryRect.Min.x = ImHasFlag(IO.KeyMods, gp.InputMap.HorizontalMod) ? plot.PlotRect.Min.x : ImMin(plot.QueryStart.x, IO.MousePos.x);
- plot.QueryRect.Max.x = ImHasFlag(IO.KeyMods, gp.InputMap.HorizontalMod) ? plot.PlotRect.Max.x : ImMax(plot.QueryStart.x, IO.MousePos.x);
- plot.QueryRect.Min.y = ImHasFlag(IO.KeyMods, gp.InputMap.VerticalMod) ? plot.PlotRect.Min.y : ImMin(plot.QueryStart.y, IO.MousePos.y);
- plot.QueryRect.Max.y = ImHasFlag(IO.KeyMods, gp.InputMap.VerticalMod) ? plot.PlotRect.Max.y : ImMax(plot.QueryStart.y, IO.MousePos.y);
- plot.QueryRect.Min -= plot.PlotRect.Min;
- plot.QueryRect.Max -= plot.PlotRect.Min;
- plot.Queried = plot.QueryRect.GetWidth() > 2 && plot.QueryRect.GetHeight() > 2;
- }
+ axis.HasRange = npd_rngh;
+ axis.RangeCond = npd_rngc;
+}
+
+//-----------------------------------------------------------------------------
+// Setup
+//-----------------------------------------------------------------------------
+
+void SetupAxis(ImAxis idx, const char* label, ImPlotAxisFlags flags) {
+ IM_ASSERT_USER_ERROR(GImPlot->CurrentPlot != NULL && !GImPlot->CurrentPlot->SetupLocked,
+ "Setup needs to be called after BeginPlot and before any setup locking functions (e.g. PlotX)!");
+ IM_ASSERT_USER_ERROR(!(ImHasFlag(flags, ImPlotAxisFlags_Time) && ImHasFlag(flags, ImPlotAxisFlags_LogScale)),
+ "ImPlotAxisFlags_Time and ImPlotAxisFlags_LogScale cannot be enabled at the same time!");
+ IM_ASSERT_USER_ERROR(!(ImHasFlag(flags, ImPlotAxisFlags_Time) && idx >= ImAxis_Y1),
+ "Y axes cannot display time formatted labels!");
+ // get plot and axis
+ ImPlotPlot& plot = *GImPlot->CurrentPlot;
+ ImPlotAxis& axis = plot.Axes[idx];
+ // set ID
+ axis.ID = plot.ID + idx + 1;
+ // check and set flags
+ if (plot.JustCreated || flags != axis.PreviousFlags)
+ axis.Flags = flags;
+ axis.PreviousFlags = flags;
+ // enable axis
+ axis.Enabled = true;
+ // set label
+ plot.SetAxisLabel(axis,label);
+ // cache colors
+ UpdateAxisColors(axis);
+}
+
+void SetupAxisLimits(ImAxis idx, double min_lim, double max_lim, ImPlotCond cond) {
+ IM_ASSERT_USER_ERROR(GImPlot->CurrentPlot != NULL && !GImPlot->CurrentPlot->SetupLocked,
+ "Setup needs to be called after BeginPlot and before any setup locking functions (e.g. PlotX)!"); // get plot and axis
+ ImPlotPlot& plot = *GImPlot->CurrentPlot;
+ ImPlotAxis& axis = plot.Axes[idx];
+ IM_ASSERT_USER_ERROR(axis.Enabled, "Axis is not enabled! Did you forget to call SetupAxis()?");
+ if (!plot.Initialized || cond == ImPlotCond_Always)
+ axis.SetRange(min_lim, max_lim);
+ axis.HasRange = true;
+ axis.RangeCond = cond;
+}
+
+void SetupAxisFormat(ImAxis idx, const char* fmt) {
+ IM_ASSERT_USER_ERROR(GImPlot->CurrentPlot != NULL && !GImPlot->CurrentPlot->SetupLocked,
+ "Setup needs to be called after BeginPlot and before any setup locking functions (e.g. PlotX)!");
+ ImPlotPlot& plot = *GImPlot->CurrentPlot;
+ ImPlotAxis& axis = plot.Axes[idx];
+ IM_ASSERT_USER_ERROR(axis.Enabled, "Axis is not enabled! Did you forget to call SetupAxis()?");
+ axis.HasFormatSpec = fmt != NULL;
+ if (fmt != NULL)
+ ImStrncpy(axis.FormatSpec,fmt,sizeof(axis.FormatSpec));
+}
+
+void SetupAxisLinks(ImAxis idx, double* min_lnk, double* max_lnk) {
+ IM_ASSERT_USER_ERROR(GImPlot->CurrentPlot != NULL && !GImPlot->CurrentPlot->SetupLocked,
+ "Setup needs to be called after BeginPlot and before any setup locking functions (e.g. PlotX)!");
+ ImPlotPlot& plot = *GImPlot->CurrentPlot;
+ ImPlotAxis& axis = plot.Axes[idx];
+ IM_ASSERT_USER_ERROR(axis.Enabled, "Axis is not enabled! Did you forget to call SetupAxis()?");
+ axis.LinkedMin = min_lnk;
+ axis.LinkedMax = max_lnk;
+ axis.PullLinks();
+}
+
+void SetupAxisFormat(ImAxis idx, ImPlotFormatter formatter, void* data) {
+ IM_ASSERT_USER_ERROR(GImPlot->CurrentPlot != NULL && !GImPlot->CurrentPlot->SetupLocked,
+ "Setup needs to be called after BeginPlot and before any setup locking functions (e.g. PlotX)!");
+ ImPlotPlot& plot = *GImPlot->CurrentPlot;
+ ImPlotAxis& axis = plot.Axes[idx];
+ IM_ASSERT_USER_ERROR(axis.Enabled, "Axis is not enabled! Did you forget to call SetupAxis()?");
+ axis.Formatter = formatter;
+ axis.FormatterData = data;
+}
+
+void SetupAxisTicks(ImAxis idx, const double* values, int n_ticks, const char* const labels[], bool show_default) {
+ IM_ASSERT_USER_ERROR(GImPlot->CurrentPlot != NULL && !GImPlot->CurrentPlot->SetupLocked,
+ "Setup needs to be called after BeginPlot and before any setup locking functions (e.g. PlotX)!");
+ ImPlotPlot& plot = *GImPlot->CurrentPlot;
+ ImPlotAxis& axis = plot.Axes[idx];
+ IM_ASSERT_USER_ERROR(axis.Enabled, "Axis is not enabled! Did you forget to call SetupAxis()?");
+ axis.ShowDefaultTicks = show_default;
+ AddTicksCustom(values,
+ labels,
+ n_ticks,
+ axis.Ticks,
+ axis.Formatter ? axis.Formatter : DefaultFormatter,
+ (axis.Formatter && axis.FormatterData) ? axis.FormatterData : axis.HasFormatSpec ? axis.FormatSpec : (void*)IMPLOT_LABEL_FORMAT);
+}
+
+void SetupAxisTicks(ImAxis idx, double v_min, double v_max, int n_ticks, const char* const labels[], bool show_default) {
+ IM_ASSERT_USER_ERROR(GImPlot->CurrentPlot != NULL && !GImPlot->CurrentPlot->SetupLocked,
+ "Setup needs to be called after BeginPlot and before any setup locking functions (e.g. PlotX)!");
+ IM_ASSERT_USER_ERROR(n_ticks > 1, "The number of ticks must be greater than 1");
+ FillRange(GImPlot->TempDouble1, n_ticks, v_min, v_max);
+ SetupAxisTicks(idx, GImPlot->TempDouble1.Data, n_ticks, labels, show_default);
+}
+
+void SetupAxes(const char* x_label, const char* y_label, ImPlotAxisFlags x_flags, ImPlotAxisFlags y_flags) {
+ SetupAxis(ImAxis_X1, x_label, x_flags);
+ SetupAxis(ImAxis_Y1, y_label, y_flags);
+}
+
+void SetupAxesLimits(double x_min, double x_max, double y_min, double y_max, ImPlotCond cond) {
+ SetupAxisLimits(ImAxis_X1, x_min, x_max, cond);
+ SetupAxisLimits(ImAxis_Y1, y_min, y_max, cond);
+}
+
+void SetupLegend(ImPlotLocation location, ImPlotLegendFlags flags) {
+ IM_ASSERT_USER_ERROR(GImPlot->CurrentPlot != NULL && !GImPlot->CurrentPlot->SetupLocked,
+ "Setup needs to be called after BeginPlot and before any setup locking functions (e.g. PlotX)!");
+ IM_ASSERT_USER_ERROR(GImPlot->CurrentItems != NULL,
+ "SetupLegend() needs to be called within an itemized context!");
+ ImPlotLegend& legend = GImPlot->CurrentItems->Legend;
+ // check and set location
+ if (location != legend.PreviousLocation)
+ legend.Location = location;
+ legend.PreviousLocation = location;
+ // check and set flags
+ if (flags != legend.PreviousFlags)
+ legend.Flags = flags;
+ legend.PreviousFlags = flags;
+}
+
+void SetupMouseText(ImPlotLocation location, ImPlotMouseTextFlags flags) {
+ IM_ASSERT_USER_ERROR(GImPlot->CurrentPlot != NULL && !GImPlot->CurrentPlot->SetupLocked,
+ "Setup needs to be called after BeginPlot and before any setup locking functions (e.g. PlotX)!");
+ GImPlot->CurrentPlot->MouseTextLocation = location;
+ GImPlot->CurrentPlot->MouseTextFlags = flags;
+}
+
+//-----------------------------------------------------------------------------
+// SetNext
+//-----------------------------------------------------------------------------
+
+void SetNextAxisLimits(ImAxis axis, double v_min, double v_max, ImPlotCond cond) {
+ ImPlotContext& gp = *GImPlot;
+ IM_ASSERT_USER_ERROR(gp.CurrentPlot == NULL, "SetNextAxisLimits() needs to be called before BeginPlot()!");
+ IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
+ gp.NextPlotData.HasRange[axis] = true;
+ gp.NextPlotData.RangeCond[axis] = cond;
+ gp.NextPlotData.Range[axis].Min = v_min;
+ gp.NextPlotData.Range[axis].Max = v_max;
+}
+
+void SetNextAxisLinks(ImAxis axis, double* link_min, double* link_max) {
+ ImPlotContext& gp = *GImPlot;
+ IM_ASSERT_USER_ERROR(gp.CurrentPlot == NULL, "SetNextAxisLinks() needs to be called before BeginPlot()!");
+ gp.NextPlotData.LinkedMin[axis] = link_min;
+ gp.NextPlotData.LinkedMax[axis] = link_max;
+}
+
+void SetNextAxisToFit(ImAxis axis) {
+ ImPlotContext& gp = *GImPlot;
+ IM_ASSERT_USER_ERROR(gp.CurrentPlot == NULL, "SetNextAxisToFit() needs to be called before BeginPlot()!");
+ gp.NextPlotData.Fit[axis] = true;
+}
+
+void SetNextAxesLimits(double x_min, double x_max, double y_min, double y_max, ImPlotCond cond) {
+ SetNextAxisLimits(ImAxis_X1, x_min, x_max, cond);
+ SetNextAxisLimits(ImAxis_Y1, y_min, y_max, cond);
+}
+
+void SetNextAxesToFit() {
+ for (int i = 0; i < ImAxis_COUNT; ++i)
+ SetNextAxisToFit(i);
+}
+
+//-----------------------------------------------------------------------------
+// BeginPlot
+//-----------------------------------------------------------------------------
+
+bool BeginPlot(const char* title_id, const ImVec2& size, ImPlotFlags flags) {
+ IM_ASSERT_USER_ERROR(GImPlot != NULL, "No current context. Did you call ImPlot::CreateContext() or ImPlot::SetCurrentContext()?");
+ IM_ASSERT_USER_ERROR(GImPlot->CurrentPlot == NULL, "Mismatched BeginPlot()/EndPlot()!");
+
+ // FRONT MATTER -----------------------------------------------------------
+
+ if (GImPlot->CurrentSubplot != NULL)
+ ImGui::PushID(GImPlot->CurrentSubplot->CurrentIdx);
+
+ // get globals
+ ImPlotContext& gp = *GImPlot;
+ ImGuiContext &G = *GImGui;
+ ImGuiWindow* Window = G.CurrentWindow;
+
+ // skip if needed
+ if (Window->SkipItems && !gp.CurrentSubplot) {
+ ResetCtxForNextPlot(GImPlot);
+ return false;
}
- // switch select to query
- if (ImHasFlag(plot.Flags, ImPlotFlags_Query) && plot.Selecting && ImHasFlag(IO.KeyMods,gp.InputMap.QueryToggleMod)) {
- plot.Selecting = plot.Selected = false;
- plot.Querying = plot.Queried = true;
- plot.QueryStart = plot.SelectStart;
- plot.QueryRect = plot.SelectRect;
+ // ID and age (TODO: keep track of plot age in frames)
+ const ImGuiID ID = Window->GetID(title_id);
+ const bool just_created = gp.Plots.GetByKey(ID) == NULL;
+ gp.CurrentPlot = gp.Plots.GetOrAddByKey(ID);
+
+ ImPlotPlot &plot = *gp.CurrentPlot;
+ plot.ID = ID;
+ plot.Items.ID = ID - 1;
+ plot.JustCreated = just_created;
+ plot.SetupLocked = false;
+
+ // check flags
+ if (plot.JustCreated)
+ plot.Flags = flags;
+ else if (flags != plot.PreviousFlags)
+ plot.Flags = flags;
+ plot.PreviousFlags = flags;
+ // setup default axes
+ if (plot.JustCreated) {
+ SetupAxis(ImAxis_X1);
+ SetupAxis(ImAxis_Y1);
}
- // switch query to select
- if (!ImHasFlag(plot.Flags, ImPlotFlags_NoBoxSelect) && plot.Querying && !ImHasFlag(IO.KeyMods, gp.InputMap.QueryToggleMod) && !IO.MouseDown[gp.InputMap.QueryButton]) {
- plot.Selecting = plot.Selected = true;
- plot.Querying = plot.Queried = false;
- plot.SelectStart = plot.QueryStart;
- plot.SelectRect = plot.QueryRect;
+
+ // reset axes
+ for (int i = 0; i < ImAxis_COUNT; ++i) {
+ plot.Axes[i].Reset();
+ UpdateAxisColors(plot.Axes[i]);
}
+ // ensure first axes enabled
+ plot.Axes[ImAxis_X1].Enabled = true;
+ plot.Axes[ImAxis_Y1].Enabled = true;
+ // set initial axes
+ plot.CurrentX = ImAxis_X1;
+ plot.CurrentY = ImAxis_Y1;
- // FIT -----------------------------------------------------------
+ // process next plot data (legacy)
+ for (int i = 0; i < ImAxis_COUNT; ++i)
+ ApplyNextPlotData(i);
- // fit from double click
- if ( IO.MouseDoubleClicked[gp.InputMap.FitButton] && plot.FrameHovered && (plot.XAxis.AllHovered || any_hov_y_axis_region) && !plot.LegendHovered && !hov_query ) {
- gp.FitThisFrame = true;
- gp.FitX = plot.XAxis.AllHovered;
- for (int i = 0; i < IMPLOT_Y_AXES; i++)
- gp.FitY[i] = plot.YAxis[i].AllHovered;
- }
- // fit from FitNextPlotAxes or auto fit
- if (gp.NextPlotData.FitX || ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_AutoFit)) {
- gp.FitThisFrame = true;
- gp.FitX = true;
+ // capture scroll with a child region
+ if (!ImHasFlag(plot.Flags, ImPlotFlags_NoChild)) {
+ ImVec2 child_size;
+ if (gp.CurrentSubplot != NULL)
+ child_size = gp.CurrentSubplot->CellSize;
+ else
+ child_size = ImVec2(size.x == 0 ? gp.Style.PlotDefaultSize.x : size.x, size.y == 0 ? gp.Style.PlotDefaultSize.y : size.y);
+ ImGui::BeginChild(title_id, child_size, false, ImGuiWindowFlags_NoScrollbar);
+ Window = ImGui::GetCurrentWindow();
+ Window->ScrollMax.y = 1.0f;
+ gp.ChildWindowMade = true;
}
- for (int i = 0; i < IMPLOT_Y_AXES; ++i) {
- if (gp.NextPlotData.FitY[i] || ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_AutoFit)) {
- gp.FitThisFrame = true;
- gp.FitY[i] = true;
- }
+ else {
+ gp.ChildWindowMade = false;
}
- // FOCUS ------------------------------------------------------------------
+ // clear text buffers
+ plot.ClearTextBuffer();
+ plot.SetTitle(title_id);
- // focus window
- if ((IO.MouseClicked[0] || IO.MouseClicked[1] || IO.MouseClicked[2]) && plot.FrameHovered)
- ImGui::FocusWindow(ImGui::GetCurrentWindow());
+ // set frame size
+ ImVec2 frame_size;
+ if (gp.CurrentSubplot != NULL)
+ frame_size = gp.CurrentSubplot->CellSize;
+ else
+ frame_size = ImGui::CalcItemSize(size, gp.Style.PlotDefaultSize.x, gp.Style.PlotDefaultSize.y);
- UpdateTransformCache();
+ if (frame_size.x < gp.Style.PlotMinSize.x && (size.x < 0.0f || gp.CurrentSubplot != NULL))
+ frame_size.x = gp.Style.PlotMinSize.x;
+ if (frame_size.y < gp.Style.PlotMinSize.y && (size.y < 0.0f || gp.CurrentSubplot != NULL))
+ frame_size.y = gp.Style.PlotMinSize.y;
- // set mouse position
- for (int i = 0; i < IMPLOT_Y_AXES; i++) {
- gp.MousePos[i] = PixelsToPlot(IO.MousePos, i);
+ plot.FrameRect = ImRect(Window->DC.CursorPos, Window->DC.CursorPos + frame_size);
+ ImGui::ItemSize(plot.FrameRect);
+ if (!ImGui::ItemAdd(plot.FrameRect, plot.ID, &plot.FrameRect) && !gp.CurrentSubplot) {
+ ResetCtxForNextPlot(GImPlot);
+ return false;
}
- // RENDER -----------------------------------------------------------------
+ // setup items (or dont)
+ if (gp.CurrentItems == NULL)
+ gp.CurrentItems = &plot.Items;
- // grid bg
- DrawList.AddRectFilled(plot.PlotRect.Min, plot.PlotRect.Max, GetStyleColorU32(ImPlotCol_PlotBg));
+ return true;
+}
+
+void SetupFinish() {
+ IM_ASSERT_USER_ERROR(GImPlot != NULL, "No current context. Did you call ImPlot::CreateContext() or ImPlot::SetCurrentContext()?");
+ IM_ASSERT_USER_ERROR(GImPlot->CurrentPlot != NULL, "SetupFinish needs to be called after BeginPlot!");
- // transform ticks (TODO: Move this into ImPlotTickCollection)
- if (gp.RenderX) {
- for (int t = 0; t < gp.XTicks.Size; t++) {
- ImPlotTick *xt = &gp.XTicks.Ticks[t];
- xt->PixelPos = PlotToPixels(xt->PlotPos, 0, 0).x;
+ ImPlotContext& gp = *GImPlot;
+ ImGuiContext& G = *GImGui;
+ ImDrawList& DrawList = *G.CurrentWindow->DrawList;
+ const ImGuiStyle& Style = G.Style;
+
+ ImPlotPlot &plot = *gp.CurrentPlot;
+
+ // lock setup
+ plot.SetupLocked = true;
+
+ // finalize axes
+ for (int i = 0; i < ImAxis_COUNT; ++i) {
+ if (plot.Axes[i].Enabled) {
+ plot.Axes[i].Constrain();
+ if (!plot.Initialized && plot.Axes[i].CanInitFit())
+ plot.FitThisFrame = plot.Axes[i].FitThisFrame = true;
}
}
- for (int i = 0; i < IMPLOT_Y_AXES; i++) {
- if (gp.RenderY[i]) {
- for (int t = 0; t < gp.YTicks[i].Size; t++) {
- ImPlotTick *yt = &gp.YTicks[i].Ticks[t];
- yt->PixelPos = PlotToPixels(0, yt->PlotPos, i).y;
- }
+
+ // setup NULL orthogonal axes
+ const bool axis_equal = ImHasFlag(plot.Flags, ImPlotFlags_Equal);
+ for (int ix = ImAxis_X1, iy = ImAxis_Y1; ix < ImAxis_Y1 || iy < ImAxis_COUNT; ++ix, ++iy) {
+ ImPlotAxis& x_axis = plot.Axes[ix];
+ ImPlotAxis& y_axis = plot.Axes[iy];
+ if (x_axis.Enabled && y_axis.Enabled) {
+ if (x_axis.OrthoAxis == NULL)
+ x_axis.OrthoAxis = &y_axis;
+ if (y_axis.OrthoAxis == NULL)
+ y_axis.OrthoAxis = &x_axis;
+ }
+ else if (x_axis.Enabled)
+ {
+ if (x_axis.OrthoAxis == NULL && !axis_equal)
+ x_axis.OrthoAxis = &plot.Axes[ImAxis_Y1];
+ }
+ else if (y_axis.Enabled) {
+ if (y_axis.OrthoAxis == NULL && !axis_equal)
+ y_axis.OrthoAxis = &plot.Axes[ImAxis_X1];
}
}
- // render grid (background)
- PushPlotClipRect(gp.Style.PlotBorderSize == 0 ? 1.0f : 0.0f);
- if (!ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_NoGridLines) && !ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_Foreground))
- RenderGridLinesX(DrawList, gp.XTicks, plot.PlotRect, plot.XAxis.ColorMaj, plot.XAxis.ColorMin, gp.Style.MajorGridSize.x, gp.Style.MinorGridSize.x);
- for (int i = 0; i < IMPLOT_Y_AXES; i++) {
- if (plot.YAxis[i].Present && !ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_NoGridLines) && !ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_Foreground))
- RenderGridLinesY(DrawList, gp.YTicks[i], plot.PlotRect, plot.YAxis[i].ColorMaj, plot.YAxis[i].ColorMin, gp.Style.MajorGridSize.y, gp.Style.MinorGridSize.y);
- }
- PopPlotClipRect();
+ // canvas/axes bb
+ plot.CanvasRect = ImRect(plot.FrameRect.Min + gp.Style.PlotPadding, plot.FrameRect.Max - gp.Style.PlotPadding);
+ plot.AxesRect = plot.FrameRect;
- // render title
- if (title_size.x > 0.0f && !ImHasFlag(plot.Flags, ImPlotFlags_NoTitle)) {
- ImU32 col = GetStyleColorU32(ImPlotCol_TitleText);
- const char* title_end = ImGui::FindRenderedTextEnd(title);
- DrawList.AddText(ImVec2(plot.CanvasRect.GetCenter().x - title_size.x * 0.5f, plot.CanvasRect.Min.y),col,title,title_end);
+ // outside legend adjustments
+ if (!ImHasFlag(plot.Flags, ImPlotFlags_NoLegend) && plot.Items.GetLegendCount() > 0 && ImHasFlag(plot.Items.Legend.Flags, ImPlotLegendFlags_Outside)) {
+ ImPlotLegend& legend = plot.Items.Legend;
+ const bool horz = ImHasFlag(legend.Flags, ImPlotLegendFlags_Horizontal);
+ const ImVec2 legend_size = CalcLegendSize(plot.Items, gp.Style.LegendInnerPadding, gp.Style.LegendSpacing, !horz);
+ const bool west = ImHasFlag(legend.Location, ImPlotLocation_West) && !ImHasFlag(legend.Location, ImPlotLocation_East);
+ const bool east = ImHasFlag(legend.Location, ImPlotLocation_East) && !ImHasFlag(legend.Location, ImPlotLocation_West);
+ const bool north = ImHasFlag(legend.Location, ImPlotLocation_North) && !ImHasFlag(legend.Location, ImPlotLocation_South);
+ const bool south = ImHasFlag(legend.Location, ImPlotLocation_South) && !ImHasFlag(legend.Location, ImPlotLocation_North);
+ if ((west && !horz) || (west && horz && !north && !south)) {
+ plot.CanvasRect.Min.x += (legend_size.x + gp.Style.LegendPadding.x);
+ plot.AxesRect.Min.x += (legend_size.x + gp.Style.PlotPadding.x);
+ }
+ if ((east && !horz) || (east && horz && !north && !south)) {
+ plot.CanvasRect.Max.x -= (legend_size.x + gp.Style.LegendPadding.x);
+ plot.AxesRect.Max.x -= (legend_size.x + gp.Style.PlotPadding.x);
+ }
+ if ((north && horz) || (north && !horz && !west && !east)) {
+ plot.CanvasRect.Min.y += (legend_size.y + gp.Style.LegendPadding.y);
+ plot.AxesRect.Min.y += (legend_size.y + gp.Style.PlotPadding.y);
+ }
+ if ((south && horz) || (south && !horz && !west && !east)) {
+ plot.CanvasRect.Max.y -= (legend_size.y + gp.Style.LegendPadding.y);
+ plot.AxesRect.Max.y -= (legend_size.y + gp.Style.PlotPadding.y);
+ }
}
- // render axis labels
- if (show_x_label) {
- const ImVec2 xLabel_size = ImGui::CalcTextSize(x_label);
- const ImVec2 xLabel_pos(plot.PlotRect.GetCenter().x - xLabel_size.x * 0.5f, plot.CanvasRect.Max.y - txt_height);
- DrawList.AddText(xLabel_pos, plot.XAxis.ColorTxt, x_label);
+ // plot bb
+ float pad_top = 0, pad_bot = 0, pad_left = 0, pad_right = 0;
+
+ // (0) calc top padding form title
+ ImVec2 title_size(0.0f, 0.0f);
+ if (plot.HasTitle())
+ title_size = ImGui::CalcTextSize(plot.GetTitle(), NULL, true);
+ if (title_size.x > 0) {
+ pad_top += title_size.y + gp.Style.LabelPadding.y;
+ plot.AxesRect.Min.y += gp.Style.PlotPadding.y + pad_top;
}
- if (show_y1_label) {
- const ImVec2 yLabel_size = CalcTextSizeVertical(y1_label);
- const ImVec2 yLabel_pos(plot.CanvasRect.Min.x, plot.PlotRect.GetCenter().y + yLabel_size.y * 0.5f);
- AddTextVertical(&DrawList, yLabel_pos, plot.YAxis[0].ColorTxt, y1_label);
- }
+ // (1) calc addition top padding and bot padding
+ PadAndDatumAxesX(plot,pad_top,pad_bot,gp.CurrentAlignmentH);
- const char* y_labels[] = {y2_label, y3_label};
- for (int i = 1; i < IMPLOT_Y_AXES; i++) {
- const char* current_label = y_labels[i-1];
- if (plot.YAxis[i].Present && current_label && !ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_NoLabel)) {
- const ImVec2 yLabel_size = CalcTextSizeVertical(current_label);
- float label_offset = (plot.YAxis[i].IsLabeled() ? gp.YTicks[i].MaxWidth + gp.Style.LabelPadding.x : 0.0f) + gp.Style.LabelPadding.x;
- const ImVec2 yLabel_pos(gp.YAxisReference[i] + label_offset, plot.PlotRect.GetCenter().y + yLabel_size.y * 0.5f);
- AddTextVertical(&DrawList, yLabel_pos, plot.YAxis[i].ColorTxt, current_label);
- }
- }
- // render tick labels
- ImGui::PushClipRect(plot.FrameRect.Min, plot.FrameRect.Max, true);
- if (!ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_NoTickLabels)) {
- for (int t = 0; t < gp.XTicks.Size; t++) {
- ImPlotTick *xt = &gp.XTicks.Ticks[t];
- if (xt->ShowLabel && xt->PixelPos >= plot.PlotRect.Min.x - 1 && xt->PixelPos <= plot.PlotRect.Max.x + 1)
- DrawList.AddText(ImVec2(xt->PixelPos - xt->LabelSize.x * 0.5f, plot.PlotRect.Max.y + gp.Style.LabelPadding.y + xt->Level * (txt_height + gp.Style.LabelPadding.y)),
- xt->Major ? plot.XAxis.ColorTxt : plot.XAxis.ColorTxt, gp.XTicks.GetText(t));
- }
- }
- for (int i = 0; i < IMPLOT_Y_AXES; i++) {
- if (plot.YAxis[i].Present && !ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_NoTickLabels)) {
- for (int t = 0; t < gp.YTicks[i].Size; t++) {
- const float x_start = gp.YAxisReference[i] + (i == 0 ? (-gp.Style.LabelPadding.x - gp.YTicks[i].Ticks[t].LabelSize.x) : gp.Style.LabelPadding.x);
- ImPlotTick *yt = &gp.YTicks[i].Ticks[t];
- if (yt->ShowLabel && yt->PixelPos >= plot.PlotRect.Min.y - 1 && yt->PixelPos <= plot.PlotRect.Max.y + 1) {
- ImVec2 start(x_start, yt->PixelPos - 0.5f * yt->LabelSize.y);
- DrawList.AddText(start, yt->Major ? plot.YAxis[i].ColorTxt : plot.YAxis[i].ColorTxt, gp.YTicks[i].GetText(t));
- }
- }
+
+ const float plot_height = plot.CanvasRect.GetHeight() - pad_top - pad_bot;
+
+ // (2) get y tick labels (needed for left/right pad)
+ for (int i = 0; i < IMPLOT_NUM_Y_AXES; i++) {
+ ImPlotAxis& axis = plot.YAxis(i);
+ if (axis.WillRender() && axis.ShowDefaultTicks) {
+ if (axis.IsLog())
+ AddTicksLogarithmic(axis.Range,
+ plot_height,
+ true,
+ axis.Ticks,
+ axis.Formatter ? axis.Formatter : DefaultFormatter,
+ (axis.Formatter && axis.FormatterData) ? axis.FormatterData : axis.HasFormatSpec ? axis.FormatSpec : (void*)IMPLOT_LABEL_FORMAT);
+ else
+ AddTicksDefault(axis.Range,
+ plot_height,
+ true,
+ axis.Ticks,
+ axis.Formatter ? axis.Formatter : DefaultFormatter,
+ (axis.Formatter && axis.FormatterData) ? axis.FormatterData : axis.HasFormatSpec ? axis.FormatSpec : (void*)IMPLOT_LABEL_FORMAT);
}
}
- ImGui::PopClipRect();
- // clear legend
- plot.LegendData.Reset();
- // push plot ID into stack
- ImGui::PushID(ID);
- return true;
-}
+ // (3) calc left/right pad
+ PadAndDatumAxesY(plot,pad_left,pad_right,gp.CurrentAlignmentV);
-//-----------------------------------------------------------------------------
-// Context Menu
-//-----------------------------------------------------------------------------
+ const float plot_width = plot.CanvasRect.GetWidth() - pad_left - pad_right;
-template <typename F>
-bool DragFloat(const char*, F*, float, F, F) {
- return false;
-}
+ // (4) get x ticks
+ for (int i = 0; i < IMPLOT_NUM_X_AXES; i++) {
+ ImPlotAxis& axis = plot.XAxis(i);
+ if (axis.WillRender() && axis.ShowDefaultTicks) {
+ if (axis.IsTime())
+ AddTicksTime(axis.Range, plot_width, axis.Ticks);
+ else if (axis.IsLog())
+ AddTicksLogarithmic(axis.Range,
+ plot_width,
+ false,
+ axis.Ticks,
+ axis.Formatter ? axis.Formatter : DefaultFormatter,
+ (axis.Formatter && axis.FormatterData) ? axis.FormatterData : axis.HasFormatSpec ? axis.FormatSpec : (void*)IMPLOT_LABEL_FORMAT);
+ else
+ AddTicksDefault(axis.Range,
+ plot_width,
+ false,
+ axis.Ticks,
+ axis.Formatter ? axis.Formatter : DefaultFormatter,
+ (axis.Formatter && axis.FormatterData) ? axis.FormatterData : axis.HasFormatSpec ? axis.FormatSpec : (void*)IMPLOT_LABEL_FORMAT);
+ }
+ }
-template <>
-bool DragFloat<double>(const char* label, double* v, float v_speed, double v_min, double v_max) {
- return ImGui::DragScalar(label, ImGuiDataType_Double, v, v_speed, &v_min, &v_max, "%.3f", 1);
-}
+ // (5) calc plot bb
+ plot.PlotRect = ImRect(plot.CanvasRect.Min + ImVec2(pad_left, pad_top), plot.CanvasRect.Max - ImVec2(pad_right, pad_bot));
-template <>
-bool DragFloat<float>(const char* label, float* v, float v_speed, float v_min, float v_max) {
- return ImGui::DragScalar(label, ImGuiDataType_Float, v, v_speed, &v_min, &v_max, "%.3f", 1);
-}
+ // HOVER------------------------------------------------------------
-inline void BeginDisabledControls(bool cond) {
- if (cond) {
- ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true);
- ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.25f);
+ // axes hover rect, pixel ranges
+ for (int i = 0; i < IMPLOT_NUM_X_AXES; ++i) {
+ ImPlotAxis& xax = plot.XAxis(i);
+ xax.HoverRect = ImRect(ImVec2(plot.PlotRect.Min.x, ImMin(xax.Datum1,xax.Datum2)),
+ ImVec2(plot.PlotRect.Max.x, ImMax(xax.Datum1,xax.Datum2)));
+ xax.PixelMin = xax.IsInverted() ? plot.PlotRect.Max.x : plot.PlotRect.Min.x;
+ xax.PixelMax = xax.IsInverted() ? plot.PlotRect.Min.x : plot.PlotRect.Max.x;
+ xax.UpdateTransformCache();
}
-}
-inline void EndDisabledControls(bool cond) {
- if (cond) {
- ImGui::PopItemFlag();
- ImGui::PopStyleVar();
+ for (int i = 0; i < IMPLOT_NUM_Y_AXES; ++i) {
+ ImPlotAxis& yax = plot.YAxis(i);
+ yax.HoverRect = ImRect(ImVec2(ImMin(yax.Datum1,yax.Datum2),plot.PlotRect.Min.y),
+ ImVec2(ImMax(yax.Datum1,yax.Datum2),plot.PlotRect.Max.y));
+ yax.PixelMin = yax.IsInverted() ? plot.PlotRect.Min.y : plot.PlotRect.Max.y;
+ yax.PixelMax = yax.IsInverted() ? plot.PlotRect.Max.y : plot.PlotRect.Min.y;
+ yax.UpdateTransformCache();
+ }
+ // Equal axis constraint. Must happen after we set Pixels
+ // constrain equal axes for primary x and y if not approximately equal
+ // constrains x to y since x pixel size depends on y labels width, and causes feedback loops in opposite case
+ if (axis_equal) {
+ for (int i = 0; i < IMPLOT_NUM_X_AXES; ++i) {
+ ImPlotAxis& x_axis = plot.XAxis(i);
+ if (x_axis.OrthoAxis == NULL)
+ continue;
+ double xar = x_axis.GetAspect();
+ double yar = x_axis.OrthoAxis->GetAspect();
+ // edge case: user has set x range this frame, so fit y to x so that we honor their request for x range
+ // NB: because of feedback across several frames, the user's x request may not be perfectly honored
+ if (x_axis.HasRange)
+ x_axis.OrthoAxis->SetAspect(xar);
+ else if (!ImAlmostEqual(xar,yar) && !x_axis.OrthoAxis->IsInputLocked())
+ x_axis.SetAspect(yar);
+ }
}
-}
-void ShowAxisContextMenu(ImPlotAxis& axis, ImPlotAxis* equal_axis, bool time_allowed) {
+ // INPUT ------------------------------------------------------------------
+ if (!ImHasFlag(plot.Flags, ImPlotFlags_NoInputs))
+ UpdateInput(plot);
- ImGui::PushItemWidth(75);
- bool always_locked = axis.IsRangeLocked() || axis.IsAutoFitting();
- bool label = !ImHasFlag(axis.Flags, ImPlotAxisFlags_NoLabel);
- bool grid = !ImHasFlag(axis.Flags, ImPlotAxisFlags_NoGridLines);
- bool ticks = !ImHasFlag(axis.Flags, ImPlotAxisFlags_NoTickMarks);
- bool labels = !ImHasFlag(axis.Flags, ImPlotAxisFlags_NoTickLabels);
- double drag_speed = (axis.Range.Size() <= DBL_EPSILON) ? DBL_EPSILON * 1.0e+13 : 0.01 * axis.Range.Size(); // recover from almost equal axis limits.
+ // fit from FitNextPlotAxes or auto fit
+ for (int i = 0; i < ImAxis_COUNT; ++i) {
+ if (gp.NextPlotData.Fit[i] || plot.Axes[i].IsAutoFitting()) {
+ plot.FitThisFrame = true;
+ plot.Axes[i].FitThisFrame = true;
+ }
+ }
- if (axis.IsTime()) {
- ImPlotTime tmin = ImPlotTime::FromDouble(axis.Range.Min);
- ImPlotTime tmax = ImPlotTime::FromDouble(axis.Range.Max);
+ // RENDER -----------------------------------------------------------------
- BeginDisabledControls(always_locked);
- ImGui::CheckboxFlags("##LockMin", (unsigned int*)&axis.Flags, ImPlotAxisFlags_LockMin);
- EndDisabledControls(always_locked);
- ImGui::SameLine();
- BeginDisabledControls(axis.IsLockedMin() || always_locked);
- if (ImGui::BeginMenu("Min Time")) {
- if (ShowTimePicker("mintime", &tmin)) {
- if (tmin >= tmax)
- tmax = AddTime(tmin, ImPlotTimeUnit_S, 1);
- axis.SetRange(tmin.ToDouble(),tmax.ToDouble());
- }
- ImGui::Separator();
- if (ShowDatePicker("mindate",&axis.PickerLevel,&axis.PickerTimeMin,&tmin,&tmax)) {
- tmin = CombineDateTime(axis.PickerTimeMin, tmin);
- if (tmin >= tmax)
- tmax = AddTime(tmin, ImPlotTimeUnit_S, 1);
- axis.SetRange(tmin.ToDouble(), tmax.ToDouble());
- }
- ImGui::EndMenu();
- }
- EndDisabledControls(axis.IsLockedMin() || always_locked);
+ const float txt_height = ImGui::GetTextLineHeight();
- BeginDisabledControls(always_locked);
- ImGui::CheckboxFlags("##LockMax", (unsigned int*)&axis.Flags, ImPlotAxisFlags_LockMax);
- EndDisabledControls(always_locked);
- ImGui::SameLine();
- BeginDisabledControls(axis.IsLockedMax() || always_locked);
- if (ImGui::BeginMenu("Max Time")) {
- if (ShowTimePicker("maxtime", &tmax)) {
- if (tmax <= tmin)
- tmin = AddTime(tmax, ImPlotTimeUnit_S, -1);
- axis.SetRange(tmin.ToDouble(),tmax.ToDouble());
- }
- ImGui::Separator();
- if (ShowDatePicker("maxdate",&axis.PickerLevel,&axis.PickerTimeMax,&tmin,&tmax)) {
- tmax = CombineDateTime(axis.PickerTimeMax, tmax);
- if (tmax <= tmin)
- tmin = AddTime(tmax, ImPlotTimeUnit_S, -1);
- axis.SetRange(tmin.ToDouble(), tmax.ToDouble());
+ // render frame
+ if (!ImHasFlag(plot.Flags, ImPlotFlags_NoFrame))
+ ImGui::RenderFrame(plot.FrameRect.Min, plot.FrameRect.Max, GetStyleColorU32(ImPlotCol_FrameBg), true, Style.FrameRounding);
+
+ // grid bg
+ DrawList.AddRectFilled(plot.PlotRect.Min, plot.PlotRect.Max, GetStyleColorU32(ImPlotCol_PlotBg));
+
+ // transform ticks
+ for (int i = 0; i < ImAxis_COUNT; i++) {
+ ImPlotAxis& axis = plot.Axes[i];
+ if (axis.WillRender()) {
+ for (int t = 0; t < axis.Ticks.Size; t++) {
+ ImPlotTick& tk = axis.Ticks.Ticks[t];
+ tk.PixelPos = IM_ROUND(axis.PlotToPixels(tk.PlotPos));
}
- ImGui::EndMenu();
}
- EndDisabledControls(axis.IsLockedMax() || always_locked);
}
- else {
- BeginDisabledControls(always_locked);
- ImGui::CheckboxFlags("##LockMin", (unsigned int*)&axis.Flags, ImPlotAxisFlags_LockMin);
- EndDisabledControls(always_locked);
- ImGui::SameLine();
- BeginDisabledControls(axis.IsLockedMin() || always_locked);
- double temp_min = axis.Range.Min;
- if (DragFloat("Min", &temp_min, (float)drag_speed, -HUGE_VAL, axis.Range.Max - DBL_EPSILON)) {
- axis.SetMin(temp_min,true);
- if (equal_axis != NULL)
- equal_axis->SetAspect(axis.GetAspect());
- }
- EndDisabledControls(axis.IsLockedMin() || always_locked);
- BeginDisabledControls(always_locked);
- ImGui::CheckboxFlags("##LockMax", (unsigned int*)&axis.Flags, ImPlotAxisFlags_LockMax);
- EndDisabledControls(always_locked);
- ImGui::SameLine();
- BeginDisabledControls(axis.IsLockedMax() || always_locked);
- double temp_max = axis.Range.Max;
- if (DragFloat("Max", &temp_max, (float)drag_speed, axis.Range.Min + DBL_EPSILON, HUGE_VAL)) {
- axis.SetMax(temp_max,true);
- if (equal_axis != NULL)
- equal_axis->SetAspect(axis.GetAspect());
- }
- EndDisabledControls(axis.IsLockedMax() || always_locked);
+ // render grid (background)
+ for (int i = 0; i < IMPLOT_NUM_X_AXES; i++) {
+ ImPlotAxis& x_axis = plot.XAxis(i);
+ if (x_axis.Enabled && x_axis.HasGridLines() && !x_axis.IsForeground())
+ RenderGridLinesX(DrawList, x_axis.Ticks, plot.PlotRect, x_axis.ColorMaj, x_axis.ColorMin, gp.Style.MajorGridSize.x, gp.Style.MinorGridSize.x);
}
-
- ImGui::Separator();
-
- ImGui::CheckboxFlags("Auto-Fit",(unsigned int*)&axis.Flags, ImPlotAxisFlags_AutoFit);
- ImGui::CheckboxFlags("Invert",(unsigned int*)&axis.Flags, ImPlotAxisFlags_Invert);
- BeginDisabledControls(axis.IsTime() && time_allowed);
- ImGui::CheckboxFlags("Log Scale",(unsigned int*)&axis.Flags, ImPlotAxisFlags_LogScale);
- EndDisabledControls(axis.IsTime() && time_allowed);
-
- if (time_allowed) {
- BeginDisabledControls(axis.IsLog());
- ImGui::CheckboxFlags("Time",(unsigned int*)&axis.Flags, ImPlotAxisFlags_Time);
- EndDisabledControls(axis.IsLog());
+ for (int i = 0; i < IMPLOT_NUM_Y_AXES; i++) {
+ ImPlotAxis& y_axis = plot.YAxis(i);
+ if (y_axis.Enabled && y_axis.HasGridLines() && !y_axis.IsForeground())
+ RenderGridLinesY(DrawList, y_axis.Ticks, plot.PlotRect, y_axis.ColorMaj, y_axis.ColorMin, gp.Style.MajorGridSize.y, gp.Style.MinorGridSize.y);
}
- ImGui::Separator();
- if (ImGui::Checkbox("Label", &label))
- ImFlipFlag(axis.Flags, ImPlotAxisFlags_NoLabel);
- if (ImGui::Checkbox("Grid Lines", &grid))
- ImFlipFlag(axis.Flags, ImPlotAxisFlags_NoGridLines);
- if (ImGui::Checkbox("Tick Marks", &ticks))
- ImFlipFlag(axis.Flags, ImPlotAxisFlags_NoTickMarks);
- if (ImGui::Checkbox("Tick Labels", &labels))
- ImFlipFlag(axis.Flags, ImPlotAxisFlags_NoTickLabels);
-}
-
-void ShowPlotContextMenu(ImPlotPlot& plot) {
- const bool equal = ImHasFlag(plot.Flags, ImPlotFlags_Equal);
- if (ImGui::BeginMenu("X-Axis")) {
- ImGui::PushID("X");
- ShowAxisContextMenu(plot.XAxis, equal ? &plot.YAxis[0] : NULL, true);
- ImGui::PopID();
- ImGui::EndMenu();
- }
- for (int i = 0; i < IMPLOT_Y_AXES; i++) {
- if (i == 1 && !ImHasFlag(plot.Flags, ImPlotFlags_YAxis2)) {
+ // render x axis button, label, tick labels
+ for (int i = 0; i < IMPLOT_NUM_X_AXES; i++) {
+ ImPlotAxis& ax = plot.XAxis(i);
+ if (!ax.Enabled)
continue;
+ if ((ax.Hovered || ax.Held) && !plot.Held)
+ DrawList.AddRectFilled(ax.HoverRect.Min, ax.HoverRect.Max, ax.Held ? ax.ColorAct : ax.ColorHov);
+ else if (ax.ColorHiLi != IM_COL32_BLACK_TRANS) {
+ DrawList.AddRectFilled(ax.HoverRect.Min, ax.HoverRect.Max, ax.ColorHiLi);
+ ax.ColorHiLi = IM_COL32_BLACK_TRANS;
}
- if (i == 2 && !ImHasFlag(plot.Flags, ImPlotFlags_YAxis3)) {
- continue;
+ else if (ax.ColorBg != IM_COL32_BLACK_TRANS) {
+ DrawList.AddRectFilled(ax.HoverRect.Min, ax.HoverRect.Max, ax.ColorBg);
}
- char buf[10] = {};
- if (i == 0) {
- snprintf(buf, sizeof(buf) - 1, "Y-Axis");
- } else {
- snprintf(buf, sizeof(buf) - 1, "Y-Axis %d", i + 1);
+ const ImPlotTickCollection& tkc = ax.Ticks;
+ const bool opp = ax.IsOpposite();
+ if (ax.HasLabel()) {
+ const char* label = plot.GetAxisLabel(ax);
+ const ImVec2 label_size = ImGui::CalcTextSize(label);
+ const float label_offset = (ax.HasTickLabels() ? ax.Ticks.MaxSize.y + gp.Style.LabelPadding.y : 0.0f)
+ + (ax.IsTime() ? txt_height + gp.Style.LabelPadding.y : 0)
+ + gp.Style.LabelPadding.y;
+ const ImVec2 label_pos(plot.PlotRect.GetCenter().x - label_size.x * 0.5f,
+ opp ? ax.Datum1 - label_offset - label_size.y : ax.Datum1 + label_offset);
+ DrawList.AddText(label_pos, ax.ColorTxt, label);
}
- if (ImGui::BeginMenu(buf)) {
- ImGui::PushID(i);
- ShowAxisContextMenu(plot.YAxis[i], (equal && i == 0) ? &plot.XAxis : NULL, false);
- ImGui::PopID();
- ImGui::EndMenu();
+ if (ax.HasTickLabels()) {
+ for (int j = 0; j < tkc.Size; ++j) {
+ const ImPlotTick& tk = tkc.Ticks[j];
+ const float datum = ax.Datum1 + (opp ? (-gp.Style.LabelPadding.y -txt_height -tk.Level * (txt_height + gp.Style.LabelPadding.y))
+ : gp.Style.LabelPadding.y + tk.Level * (txt_height + gp.Style.LabelPadding.y));
+ if (tk.ShowLabel && tk.PixelPos >= plot.PlotRect.Min.x - 1 && tk.PixelPos <= plot.PlotRect.Max.x + 1) {
+ ImVec2 start(tk.PixelPos - 0.5f * tk.LabelSize.x, datum);
+ DrawList.AddText(start, ax.ColorTxt, tkc.GetText(j));
+ }
+ }
}
}
- ImGui::Separator();
- if ((ImGui::BeginMenu("Settings"))) {
- if (ImGui::MenuItem("Anti-Aliased Lines",NULL,ImHasFlag(plot.Flags, ImPlotFlags_AntiAliased)))
- ImFlipFlag(plot.Flags, ImPlotFlags_AntiAliased);
- if (ImGui::MenuItem("Equal", NULL, ImHasFlag(plot.Flags, ImPlotFlags_Equal)))
- ImFlipFlag(plot.Flags, ImPlotFlags_Equal);
- if (ImGui::MenuItem("Box Select",NULL,!ImHasFlag(plot.Flags, ImPlotFlags_NoBoxSelect)))
- ImFlipFlag(plot.Flags, ImPlotFlags_NoBoxSelect);
- if (ImGui::MenuItem("Query",NULL,ImHasFlag(plot.Flags, ImPlotFlags_Query)))
- ImFlipFlag(plot.Flags, ImPlotFlags_Query);
- if (ImGui::MenuItem("Title",NULL,!ImHasFlag(plot.Flags, ImPlotFlags_NoTitle)))
- ImFlipFlag(plot.Flags, ImPlotFlags_NoTitle);
- if (ImGui::MenuItem("Mouse Position",NULL,!ImHasFlag(plot.Flags, ImPlotFlags_NoMousePos)))
- ImFlipFlag(plot.Flags, ImPlotFlags_NoMousePos);
- if (ImGui::MenuItem("Crosshairs",NULL,ImHasFlag(plot.Flags, ImPlotFlags_Crosshairs)))
- ImFlipFlag(plot.Flags, ImPlotFlags_Crosshairs);
- if ((ImGui::BeginMenu("Legend"))) {
- const float s = ImGui::GetFrameHeight();
- if (ImGui::RadioButton("H", plot.LegendOrientation == ImPlotOrientation_Horizontal))
- plot.LegendOrientation = ImPlotOrientation_Horizontal;
- ImGui::SameLine();
- if (ImGui::RadioButton("V", plot.LegendOrientation == ImPlotOrientation_Vertical))
- plot.LegendOrientation = ImPlotOrientation_Vertical;
- ImGui::Checkbox("Outside", &plot.LegendOutside);
- ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(1,1));
- if (ImGui::Button("##NW",ImVec2(1.5f*s,s))) { plot.LegendLocation = ImPlotLocation_NorthWest; } ImGui::SameLine();
- if (ImGui::Button("##N", ImVec2(1.5f*s,s))) { plot.LegendLocation = ImPlotLocation_North; } ImGui::SameLine();
- if (ImGui::Button("##NE",ImVec2(1.5f*s,s))) { plot.LegendLocation = ImPlotLocation_NorthEast; }
- if (ImGui::Button("##W", ImVec2(1.5f*s,s))) { plot.LegendLocation = ImPlotLocation_West; } ImGui::SameLine();
- if (ImGui::Button("##C", ImVec2(1.5f*s,s))) { plot.LegendLocation = ImPlotLocation_Center; } ImGui::SameLine();
- if (ImGui::Button("##E", ImVec2(1.5f*s,s))) { plot.LegendLocation = ImPlotLocation_East; }
- if (ImGui::Button("##SW",ImVec2(1.5f*s,s))) { plot.LegendLocation = ImPlotLocation_SouthWest; } ImGui::SameLine();
- if (ImGui::Button("##S", ImVec2(1.5f*s,s))) { plot.LegendLocation = ImPlotLocation_South; } ImGui::SameLine();
- if (ImGui::Button("##SE",ImVec2(1.5f*s,s))) { plot.LegendLocation = ImPlotLocation_SouthEast; }
- ImGui::PopStyleVar();
- ImGui::EndMenu();
+ // render y axis button, label, tick labels
+ for (int i = 0; i < IMPLOT_NUM_Y_AXES; i++) {
+ ImPlotAxis& ax = plot.YAxis(i);
+ if (!ax.Enabled)
+ continue;
+ if ((ax.Hovered || ax.Held) && !plot.Held)
+ DrawList.AddRectFilled(ax.HoverRect.Min, ax.HoverRect.Max, ax.Held ? ax.ColorAct : ax.ColorHov);
+ else if (ax.ColorHiLi != IM_COL32_BLACK_TRANS) {
+ DrawList.AddRectFilled(ax.HoverRect.Min, ax.HoverRect.Max, ax.ColorHiLi);
+ ax.ColorHiLi = IM_COL32_BLACK_TRANS;
+ }
+ else if (ax.ColorBg != IM_COL32_BLACK_TRANS) {
+ DrawList.AddRectFilled(ax.HoverRect.Min, ax.HoverRect.Max, ax.ColorBg);
+ }
+ const ImPlotTickCollection& tkc = ax.Ticks;
+ const bool opp = ax.IsOpposite();
+ if (ax.HasLabel()) {
+ const char* label = plot.GetAxisLabel(ax);
+ const ImVec2 label_size = CalcTextSizeVertical(label);
+ const float label_offset = (ax.HasTickLabels() ? ax.Ticks.MaxSize.x + gp.Style.LabelPadding.x : 0.0f)
+ + gp.Style.LabelPadding.x;
+ const ImVec2 label_pos(opp ? ax.Datum1 + label_offset : ax.Datum1 - label_offset - label_size.x,
+ plot.PlotRect.GetCenter().y + label_size.y * 0.5f);
+ AddTextVertical(&DrawList, label_pos, ax.ColorTxt, label);
+ }
+ if (ax.HasTickLabels()) {
+ for (int j = 0; j < tkc.Size; ++j) {
+ const ImPlotTick& tk = tkc.Ticks[j];
+ const float datum = ax.Datum1 + (opp ? gp.Style.LabelPadding.x : (-gp.Style.LabelPadding.x - tk.LabelSize.x));
+ if (tk.ShowLabel && tk.PixelPos >= plot.PlotRect.Min.y - 1 && tk.PixelPos <= plot.PlotRect.Max.y + 1) {
+ ImVec2 start(datum, tk.PixelPos - 0.5f * tk.LabelSize.y);
+ DrawList.AddText(start, ax.ColorTxt, tkc.GetText(j));
+ }
+ }
}
- ImGui::EndMenu();
- }
- if (ImGui::MenuItem("Legend",NULL,!ImHasFlag(plot.Flags, ImPlotFlags_NoLegend))) {
- ImFlipFlag(plot.Flags, ImPlotFlags_NoLegend);
}
+
+
+ // clear legend (TODO: put elsewhere)
+ plot.Items.Legend.Reset();
+ // push ID to set item hashes (NB: !!!THIS PROBABLY NEEDS TO BE IN BEGIN PLOT!!!!)
+ ImGui::PushOverrideID(gp.CurrentItems->ID);
}
//-----------------------------------------------------------------------------
@@ -2224,67 +2626,96 @@ void ShowPlotContextMenu(ImPlotPlot& plot) {
void EndPlot() {
IM_ASSERT_USER_ERROR(GImPlot != NULL, "No current context. Did you call ImPlot::CreateContext() or ImPlot::SetCurrentContext()?");
+ IM_ASSERT_USER_ERROR(GImPlot->CurrentPlot != NULL, "Mismatched BeginPlot()/EndPlot()!");
+
+ SetupLock();
+
ImPlotContext& gp = *GImPlot;
- IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "Mismatched BeginPlot()/EndPlot()!");
ImGuiContext &G = *GImGui;
- ImPlotPlot &plot = *gp.CurrentPlot;
+ ImPlotPlot &plot = *gp.CurrentPlot;
ImGuiWindow * Window = G.CurrentWindow;
ImDrawList & DrawList = *Window->DrawList;
const ImGuiIO & IO = ImGui::GetIO();
- // AXIS STATES ------------------------------------------------------------
+ // FINAL RENDER -----------------------------------------------------------
- const bool any_y_dragging = plot.YAxis[0].Dragging || plot.YAxis[1].Dragging || plot.YAxis[2].Dragging;
+ const bool render_border = gp.Style.PlotBorderSize > 0 && gp.Style.Colors[ImPlotCol_PlotBorder].w > 0;
+ const bool any_x_held = plot.Held || AnyAxesHeld(&plot.Axes[ImAxis_X1], IMPLOT_NUM_X_AXES);
+ const bool any_y_held = plot.Held || AnyAxesHeld(&plot.Axes[ImAxis_Y1], IMPLOT_NUM_Y_AXES);
- // FINAL RENDER -----------------------------------------------------------
+ ImGui::PushClipRect(plot.FrameRect.Min, plot.FrameRect.Max, true);
// render grid (foreground)
- PushPlotClipRect(gp.Style.PlotBorderSize == 0 ? 1.0f : 0.0f);
- if (!ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_NoGridLines) && ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_Foreground))
- RenderGridLinesX(DrawList, gp.XTicks, plot.PlotRect, plot.XAxis.ColorMaj, plot.XAxis.ColorMaj, gp.Style.MajorGridSize.x, gp.Style.MinorGridSize.x);
- for (int i = 0; i < IMPLOT_Y_AXES; i++) {
- if (plot.YAxis[i].Present && !ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_NoGridLines) && ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_Foreground))
- RenderGridLinesY(DrawList, gp.YTicks[i], plot.PlotRect, plot.YAxis[i].ColorMaj, plot.YAxis[i].ColorMin, gp.Style.MajorGridSize.y, gp.Style.MinorGridSize.y);
+ for (int i = 0; i < IMPLOT_NUM_X_AXES; i++) {
+ ImPlotAxis& x_axis = plot.XAxis(i);
+ if (x_axis.Enabled && x_axis.HasGridLines() && x_axis.IsForeground())
+ RenderGridLinesX(DrawList, x_axis.Ticks, plot.PlotRect, x_axis.ColorMaj, x_axis.ColorMin, gp.Style.MajorGridSize.x, gp.Style.MinorGridSize.x);
+ }
+ for (int i = 0; i < IMPLOT_NUM_Y_AXES; i++) {
+ ImPlotAxis& y_axis = plot.YAxis(i);
+ if (y_axis.Enabled && y_axis.HasGridLines() && y_axis.IsForeground())
+ RenderGridLinesY(DrawList, y_axis.Ticks, plot.PlotRect, y_axis.ColorMaj, y_axis.ColorMin, gp.Style.MajorGridSize.y, gp.Style.MinorGridSize.y);
}
- PopPlotClipRect();
- // render x-ticks
- PushPlotClipRect();
- if (!ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_NoTickMarks)) {
- for (int t = 0; t < gp.XTicks.Size; t++) {
- ImPlotTick *xt = &gp.XTicks.Ticks[t];
- if (xt->Level == 0)
- DrawList.AddLine(ImVec2(xt->PixelPos, plot.PlotRect.Max.y),
- ImVec2(xt->PixelPos, plot.PlotRect.Max.y - (xt->Major ? gp.Style.MajorTickLen.x : gp.Style.MinorTickLen.x)),
- plot.XAxis.ColorMaj,
- xt->Major ? gp.Style.MajorTickSize.x : gp.Style.MinorTickSize.x);
- }
+
+ // render title
+ if (plot.HasTitle()) {
+ ImU32 col = GetStyleColorU32(ImPlotCol_TitleText);
+ AddTextCentered(&DrawList,ImVec2(plot.PlotRect.GetCenter().x, plot.CanvasRect.Min.y),col,plot.GetTitle());
}
- PopPlotClipRect();
- // render y-ticks
- ImGui::PushClipRect(plot.PlotRect.Min, ImVec2(plot.FrameRect.Max.x, plot.PlotRect.Max.y), true);
- int axis_count = 0;
- for (int i = 0; i < IMPLOT_Y_AXES; i++) {
- if (!plot.YAxis[i].Present) { continue; }
- axis_count++;
- float x_start = gp.YAxisReference[i];
- if (!ImHasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_NoTickMarks)) {
- float direction = (i == 0) ? 1.0f : -1.0f;
- bool no_major = axis_count >= 3;
- for (int t = 0; t < gp.YTicks[i].Size; t++) {
- ImPlotTick *yt = &gp.YTicks[i].Ticks[t];
- ImVec2 start = ImVec2(x_start, yt->PixelPos);
- DrawList.AddLine(start,
- start + ImVec2(direction * ((!no_major && yt->Major) ? gp.Style.MajorTickLen.y : gp.Style.MinorTickLen.y), 0),
- plot.YAxis[i].ColorMaj,
- (!no_major && yt->Major) ? gp.Style.MajorTickSize.y : gp.Style.MinorTickSize.y);
+ // render x ticks
+ int count_B = 0, count_T = 0;
+ for (int i = 0; i < IMPLOT_NUM_X_AXES; i++) {
+ const ImPlotAxis& ax = plot.XAxis(i);
+ if (!ax.Enabled)
+ continue;
+ const ImPlotTickCollection& tkc = ax.Ticks;
+ const bool opp = ax.IsOpposite();
+ const bool aux = ((opp && count_T > 0)||(!opp && count_B > 0));
+ if (ax.HasTickMarks()) {
+ const float direction = opp ? 1.0f : -1.0f;
+ for (int j = 0; j < tkc.Size; ++j) {
+ const ImPlotTick& tk = tkc.Ticks[j];
+ if (tk.Level != 0 || tk.PixelPos < plot.PlotRect.Min.x || tk.PixelPos > plot.PlotRect.Max.x)
+ continue;
+ const ImVec2 start(tk.PixelPos, ax.Datum1);
+ const float len = (!aux && tk.Major) ? gp.Style.MajorTickLen.x : gp.Style.MinorTickLen.x;
+ const float thk = (!aux && tk.Major) ? gp.Style.MajorTickSize.x : gp.Style.MinorTickSize.x;
+ DrawList.AddLine(start, start + ImVec2(0,direction*len), ax.ColorTick, thk);
}
+ if (aux || !render_border)
+ DrawList.AddLine(ImVec2(plot.PlotRect.Min.x,ax.Datum1), ImVec2(plot.PlotRect.Max.x,ax.Datum1), ax.ColorTick, gp.Style.MinorTickSize.x);
}
- if (axis_count >= 3) {
- // Draw a bar next to the ticks to act as a visual separator.
- DrawList.AddLine(ImVec2(x_start, plot.PlotRect.Min.y), ImVec2(x_start, plot.PlotRect.Max.y), GetStyleColorU32(ImPlotCol_YAxisGrid3), 1);
+ count_B += !opp;
+ count_T += opp;
+ }
+
+ // render y ticks
+ int count_L = 0, count_R = 0;
+ for (int i = 0; i < IMPLOT_NUM_Y_AXES; i++) {
+ const ImPlotAxis& ax = plot.YAxis(i);
+ if (!ax.Enabled)
+ continue;
+ const ImPlotTickCollection& tkc = ax.Ticks;
+ const bool opp = ax.IsOpposite();
+ const bool aux = ((opp && count_R > 0)||(!opp && count_L > 0));
+ if (ax.HasTickMarks()) {
+ const float direction = opp ? -1.0f : 1.0f;
+ for (int j = 0; j < tkc.Size; ++j) {
+ const ImPlotTick& tk = tkc.Ticks[j];
+ if (tk.Level != 0 || tk.PixelPos < plot.PlotRect.Min.y || tk.PixelPos > plot.PlotRect.Max.y)
+ continue;
+ const ImVec2 start(ax.Datum1, tk.PixelPos);
+ const float len = (!aux && tk.Major) ? gp.Style.MajorTickLen.y : gp.Style.MinorTickLen.y;
+ const float thk = (!aux && tk.Major) ? gp.Style.MajorTickSize.y : gp.Style.MinorTickSize.y;
+ DrawList.AddLine(start, start + ImVec2(direction*len,0), ax.ColorTick, thk);
+ }
+ if (aux || !render_border)
+ DrawList.AddLine(ImVec2(ax.Datum1, plot.PlotRect.Min.y), ImVec2(ax.Datum1, plot.PlotRect.Max.y), ax.ColorTick, gp.Style.MinorTickSize.y);
}
+ count_L += !opp;
+ count_R += opp;
}
ImGui::PopClipRect();
@@ -2331,12 +2762,9 @@ void EndPlot() {
// render selection
if (plot.Selected)
RenderSelectionRect(DrawList, plot.SelectRect.Min + plot.PlotRect.Min, plot.SelectRect.Max + plot.PlotRect.Min, GetStyleColorVec4(ImPlotCol_Selection));
- // render query
- if (plot.Queried)
- RenderSelectionRect(DrawList, plot.QueryRect.Min + plot.PlotRect.Min, plot.QueryRect.Max + plot.PlotRect.Min, GetStyleColorVec4(ImPlotCol_Query));
// render crosshairs
- if (ImHasFlag(plot.Flags, ImPlotFlags_Crosshairs) && plot.PlotHovered && !(plot.XAxis.Dragging || any_y_dragging) && !plot.Selecting && !plot.Querying && !plot.LegendHovered) {
+ if (ImHasFlag(plot.Flags, ImPlotFlags_Crosshairs) && plot.Hovered && !(any_x_held || any_y_held) && !plot.Selecting && !plot.Items.Legend.Hovered) {
ImGui::SetMouseCursor(ImGuiMouseCursor_None);
ImVec2 xy = IO.MousePos;
ImVec2 h1(plot.PlotRect.Min.x, xy.y);
@@ -2355,382 +2783,775 @@ void EndPlot() {
}
// render mouse pos
- if (!ImHasFlag(plot.Flags, ImPlotFlags_NoMousePos) && plot.PlotHovered) {
- char buffer[128] = {};
- ImBufferWriter writer(buffer, sizeof(buffer));
- // x
- if (ImHasFlag(plot.XAxis.Flags, ImPlotAxisFlags_Time)) {
- ImPlotTimeUnit unit = GetUnitForRange(plot.XAxis.Range.Size() / (plot.PlotRect.GetWidth() / 100));
- const int written = FormatDateTime(ImPlotTime::FromDouble(gp.MousePos[0].x), &writer.Buffer[writer.Pos], writer.Size - writer.Pos - 1, GetDateTimeFmt(TimeFormatMouseCursor, unit));
- if (written > 0)
- writer.Pos += ImMin(written, writer.Size - writer.Pos - 1);
- }
- else {
- writer.Write(GetFormatX(), RoundAxisValue(plot.XAxis, gp.XTicks, gp.MousePos[0].x));
+ if (!ImHasFlag(plot.Flags, ImPlotFlags_NoMouseText) && (plot.Hovered || ImHasFlag(plot.MouseTextFlags, ImPlotMouseTextFlags_ShowAlways))) {
+
+ const bool no_aux = ImHasFlag(plot.MouseTextFlags, ImPlotMouseTextFlags_NoAuxAxes);
+ const bool no_fmt = ImHasFlag(plot.MouseTextFlags, ImPlotMouseTextFlags_NoFormat);
+
+ ImGuiTextBuffer& builder = gp.MousePosStringBuilder;
+ builder.Buf.shrink(0);
+ char buff[IMPLOT_LABEL_MAX_SIZE];
+
+ const int num_x = no_aux ? 1 : IMPLOT_NUM_X_AXES;
+ for (int i = 0; i < num_x; ++i) {
+ ImPlotAxis& x_axis = plot.XAxis(i);
+ if (!x_axis.Enabled)
+ continue;
+ if (i > 0)
+ builder.append(", (");
+ double v = x_axis.PixelsToPlot(IO.MousePos.x);
+ no_fmt ? DefaultFormatter(v,buff,IMPLOT_LABEL_MAX_SIZE,(void*)IMPLOT_LABEL_FORMAT)
+ : LabelAxisValue(x_axis,v,buff,IMPLOT_LABEL_MAX_SIZE,true);
+ builder.append(buff);
+ if (i > 0)
+ builder.append(")");
}
- // y1
- writer.Write(", ");
- writer.Write(GetFormatY(0), RoundAxisValue(plot.YAxis[0], gp.YTicks[0], gp.MousePos[0].y));
- // y2
- if (ImHasFlag(plot.Flags, ImPlotFlags_YAxis2)) {
- writer.Write(", (");
- writer.Write(GetFormatY(1), RoundAxisValue(plot.YAxis[1], gp.YTicks[1], gp.MousePos[1].y));
- writer.Write(")");
+ builder.append(", ");
+ const int num_y = no_aux ? 1 : IMPLOT_NUM_Y_AXES;
+ for (int i = 0; i < num_y; ++i) {
+ ImPlotAxis& y_axis = plot.YAxis(i);
+ if (!y_axis.Enabled)
+ continue;
+ if (i > 0)
+ builder.append(", (");
+ double v = y_axis.PixelsToPlot(IO.MousePos.y);
+ no_fmt ? DefaultFormatter(v,buff,IMPLOT_LABEL_MAX_SIZE,(void*)IMPLOT_LABEL_FORMAT)
+ : LabelAxisValue(y_axis,v,buff,IMPLOT_LABEL_MAX_SIZE,true);
+ builder.append(buff);
+ if (i > 0)
+ builder.append(")");
}
- // y3
- if (ImHasFlag(plot.Flags, ImPlotFlags_YAxis3)) {
- writer.Write(", (");
- writer.Write(GetFormatY(2), RoundAxisValue(plot.YAxis[2], gp.YTicks[2], gp.MousePos[2].y));
- writer.Write(")");
+
+ if (!builder.empty()) {
+ const ImVec2 size = ImGui::CalcTextSize(builder.c_str());
+ const ImVec2 pos = GetLocationPos(plot.PlotRect, size, plot.MouseTextLocation, gp.Style.MousePosPadding);
+ DrawList.AddText(pos, GetStyleColorU32(ImPlotCol_InlayText), builder.c_str());
}
- const ImVec2 size = ImGui::CalcTextSize(buffer);
- const ImVec2 pos = GetLocationPos(plot.PlotRect, size, plot.MousePosLocation, gp.Style.MousePosPadding);
- DrawList.AddText(pos, GetStyleColorU32(ImPlotCol_InlayText), buffer);
}
PopPlotClipRect();
+ // axis side switch
+ if (!plot.Held) {
+ ImVec2 mouse_pos = ImGui::GetIO().MousePos;
+ ImRect trigger_rect = plot.PlotRect;
+ trigger_rect.Expand(-10);
+ for (int i = 0; i < IMPLOT_NUM_X_AXES; ++i) {
+ ImPlotAxis& x_axis = plot.XAxis(i);
+ if (x_axis.Held && plot.PlotRect.Contains(mouse_pos)) {
+ const bool opp = ImHasFlag(x_axis.Flags, ImPlotAxisFlags_Opposite);
+ if (!opp) {
+ ImRect rect(plot.PlotRect.Min.x - 5, plot.PlotRect.Min.y - 5,
+ plot.PlotRect.Max.x + 5, plot.PlotRect.Min.y + 5);
+ if (mouse_pos.y < plot.PlotRect.Max.y - 10)
+ DrawList.AddRectFilled(rect.Min, rect.Max, x_axis.ColorHov);
+ if (rect.Contains(mouse_pos))
+ x_axis.Flags |= ImPlotAxisFlags_Opposite;
+ }
+ else {
+ ImRect rect(plot.PlotRect.Min.x - 5, plot.PlotRect.Max.y - 5,
+ plot.PlotRect.Max.x + 5, plot.PlotRect.Max.y + 5);
+ if (mouse_pos.y > plot.PlotRect.Min.y + 10)
+ DrawList.AddRectFilled(rect.Min, rect.Max, x_axis.ColorHov);
+ if (rect.Contains(mouse_pos))
+ x_axis.Flags &= ~ImPlotAxisFlags_Opposite;
+ }
+ }
+ }
+ for (int i = 0; i < IMPLOT_NUM_Y_AXES; ++i) {
+ ImPlotAxis& y_axis = plot.YAxis(i);
+ if (y_axis.Held && plot.PlotRect.Contains(mouse_pos)) {
+ const bool opp = ImHasFlag(y_axis.Flags, ImPlotAxisFlags_Opposite);
+ if (!opp) {
+ ImRect rect(plot.PlotRect.Max.x - 5, plot.PlotRect.Min.y - 5,
+ plot.PlotRect.Max.x + 5, plot.PlotRect.Max.y + 5);
+ if (mouse_pos.x > plot.PlotRect.Min.x + 10)
+ DrawList.AddRectFilled(rect.Min, rect.Max, y_axis.ColorHov);
+ if (rect.Contains(mouse_pos))
+ y_axis.Flags |= ImPlotAxisFlags_Opposite;
+ }
+ else {
+ ImRect rect(plot.PlotRect.Min.x - 5, plot.PlotRect.Min.y - 5,
+ plot.PlotRect.Min.x + 5, plot.PlotRect.Max.y + 5);
+ if (mouse_pos.x < plot.PlotRect.Max.x - 10)
+ DrawList.AddRectFilled(rect.Min, rect.Max, y_axis.ColorHov);
+ if (rect.Contains(mouse_pos))
+ y_axis.Flags &= ~ImPlotAxisFlags_Opposite;
+ }
+ }
+ }
+ }
+
// reset legend hovers
- plot.LegendHovered = false;
- for (int i = 0; i < plot.Items.GetSize(); ++i)
- plot.Items.GetByIndex(i)->LegendHovered = false;
+ plot.Items.Legend.Hovered = false;
+ for (int i = 0; i < plot.Items.GetItemCount(); ++i)
+ plot.Items.GetItemByIndex(i)->LegendHovered = false;
// render legend
- if (!ImHasFlag(plot.Flags, ImPlotFlags_NoLegend) && plot.GetLegendCount() > 0) {
- const ImVec2 legend_size = CalcLegendSize(plot, gp.Style.LegendInnerPadding, gp.Style.LegendSpacing, plot.LegendOrientation);
- const ImVec2 legend_pos = GetLocationPos(plot.LegendOutside ? plot.FrameRect : plot.PlotRect,
+ if (!ImHasFlag(plot.Flags, ImPlotFlags_NoLegend) && plot.Items.GetLegendCount() > 0) {
+ ImPlotLegend& legend = plot.Items.Legend;
+ const bool legend_out = ImHasFlag(legend.Flags, ImPlotLegendFlags_Outside);
+ const bool legend_horz = ImHasFlag(legend.Flags, ImPlotLegendFlags_Horizontal);
+ const ImVec2 legend_size = CalcLegendSize(plot.Items, gp.Style.LegendInnerPadding, gp.Style.LegendSpacing, !legend_horz);
+ const ImVec2 legend_pos = GetLocationPos(legend_out ? plot.FrameRect : plot.PlotRect,
legend_size,
- plot.LegendLocation,
- plot.LegendOutside ? gp.Style.PlotPadding : gp.Style.LegendPadding);
- plot.LegendRect = ImRect(legend_pos, legend_pos + legend_size);
+ legend.Location,
+ legend_out ? gp.Style.PlotPadding : gp.Style.LegendPadding);
+ legend.Rect = ImRect(legend_pos, legend_pos + legend_size);
// test hover
- plot.LegendHovered = plot.FrameHovered && plot.LegendRect.Contains(IO.MousePos);
+ legend.Hovered = ImGui::IsWindowHovered() && legend.Rect.Contains(IO.MousePos);
- if (plot.LegendOutside)
+ if (legend_out)
ImGui::PushClipRect(plot.FrameRect.Min, plot.FrameRect.Max, true);
else
PushPlotClipRect();
ImU32 col_bg = GetStyleColorU32(ImPlotCol_LegendBg);
ImU32 col_bd = GetStyleColorU32(ImPlotCol_LegendBorder);
- DrawList.AddRectFilled(plot.LegendRect.Min, plot.LegendRect.Max, col_bg);
- DrawList.AddRect(plot.LegendRect.Min, plot.LegendRect.Max, col_bd);
- ShowLegendEntries(plot, plot.LegendRect, plot.LegendHovered, gp.Style.LegendInnerPadding, gp.Style.LegendSpacing, plot.LegendOrientation, DrawList);
+ DrawList.AddRectFilled(legend.Rect.Min, legend.Rect.Max, col_bg);
+ DrawList.AddRect(legend.Rect.Min, legend.Rect.Max, col_bd);
+ bool legend_contextable = ShowLegendEntries(plot.Items, legend.Rect, legend.Hovered, gp.Style.LegendInnerPadding, gp.Style.LegendSpacing, !legend_horz, DrawList)
+ && !ImHasFlag(legend.Flags, ImPlotLegendFlags_NoMenus);
+
+ // main ctx menu
+ if (gp.OpenContextThisFrame && legend_contextable && !ImHasFlag(plot.Flags, ImPlotFlags_NoMenus))
+ ImGui::OpenPopup("##LegendContext");
ImGui::PopClipRect();
+ if (ImGui::BeginPopup("##LegendContext")) {
+ ImGui::Text("Legend"); ImGui::Separator();
+ if (ShowLegendContextMenu(legend, !ImHasFlag(plot.Flags, ImPlotFlags_NoLegend)))
+ ImFlipFlag(plot.Flags, ImPlotFlags_NoLegend);
+ ImGui::EndPopup();
+ }
}
else {
- plot.LegendRect = ImRect();
- }
- if (plot.LegendFlipSideNextFrame) {
- plot.LegendOutside = !plot.LegendOutside;
- plot.LegendFlipSideNextFrame = false;
+ plot.Items.Legend.Rect = ImRect();
}
// render border
- if (gp.Style.PlotBorderSize > 0)
+ if (render_border)
DrawList.AddRect(plot.PlotRect.Min, plot.PlotRect.Max, GetStyleColorU32(ImPlotCol_PlotBorder), 0, ImDrawFlags_RoundCornersAll, gp.Style.PlotBorderSize);
+ // render tags
+ for (int i = 0; i < gp.Tags.Size; ++i) {
+ ImPlotTag& tag = gp.Tags.Tags[i];
+ ImPlotAxis& axis = plot.Axes[tag.Axis];
+ if (!axis.Enabled || !axis.Range.Contains(tag.Value))
+ continue;
+ const char* txt = gp.Tags.GetText(i);
+ ImVec2 text_size = ImGui::CalcTextSize(txt);
+ ImVec2 size = text_size + gp.Style.AnnotationPadding * 2;
+ ImVec2 pos;
+ axis.Ticks.OverrideSizeLate(size);
+ float pix = IM_ROUND(axis.PlotToPixels(tag.Value));
+ if (axis.Vertical) {
+ if (axis.IsOpposite()) {
+ pos = ImVec2(axis.Datum1 + gp.Style.LabelPadding.x, pix - size.y * 0.5f);
+ DrawList.AddTriangleFilled(ImVec2(axis.Datum1,pix), pos, pos + ImVec2(0,size.y), tag.ColorBg);
+ }
+ else {
+ pos = ImVec2(axis.Datum1 - size.x - gp.Style.LabelPadding.x, pix - size.y * 0.5f);
+ DrawList.AddTriangleFilled(pos + ImVec2(size.x,0), ImVec2(axis.Datum1,pix), pos+size, tag.ColorBg);
+ }
+ }
+ else {
+ if (axis.IsOpposite()) {
+ pos = ImVec2(pix - size.x * 0.5f, axis.Datum1 - size.y - gp.Style.LabelPadding.y );
+ DrawList.AddTriangleFilled(pos + ImVec2(0,size.y), pos + size, ImVec2(pix,axis.Datum1), tag.ColorBg);
+ }
+ else {
+ pos = ImVec2(pix - size.x * 0.5f, axis.Datum1 + gp.Style.LabelPadding.y);
+ DrawList.AddTriangleFilled(pos, ImVec2(pix,axis.Datum1), pos + ImVec2(size.x, 0), tag.ColorBg);
+ }
+ }
+ DrawList.AddRectFilled(pos,pos+size,tag.ColorBg);
+ DrawList.AddText(pos+gp.Style.AnnotationPadding,tag.ColorFg,txt);
+ }
+
// FIT DATA --------------------------------------------------------------
const bool axis_equal = ImHasFlag(plot.Flags, ImPlotFlags_Equal);
- if (gp.FitThisFrame && (gp.VisibleItemCount > 0 || plot.Queried)) {
- if (gp.FitX) {
- const double ext_size = gp.ExtentsX.Size() * 0.5;
- gp.ExtentsX.Min -= ext_size * gp.Style.FitPadding.x;
- gp.ExtentsX.Max += ext_size * gp.Style.FitPadding.x;
- if (!plot.XAxis.IsLockedMin() && !ImNanOrInf(gp.ExtentsX.Min))
- plot.XAxis.Range.Min = (gp.ExtentsX.Min);
- if (!plot.XAxis.IsLockedMax() && !ImNanOrInf(gp.ExtentsX.Max))
- plot.XAxis.Range.Max = (gp.ExtentsX.Max);
- if (ImAlmostEqual(plot.XAxis.Range.Max, plot.XAxis.Range.Min)) {
- plot.XAxis.Range.Max += 0.5;
- plot.XAxis.Range.Min -= 0.5;
+ if (plot.FitThisFrame) {
+ for (int i = 0; i < IMPLOT_NUM_X_AXES; i++) {
+ ImPlotAxis& x_axis = plot.XAxis(i);
+ if (x_axis.FitThisFrame) {
+ x_axis.ApplyFit(gp.Style.FitPadding.x);
+ if (axis_equal && x_axis.OrthoAxis != NULL) {
+ double aspect = x_axis.GetAspect();
+ ImPlotAxis& y_axis = *x_axis.OrthoAxis;
+ if (y_axis.FitThisFrame) {
+ y_axis.ApplyFit(gp.Style.FitPadding.y);
+ y_axis.FitThisFrame = false;
+ aspect = ImMax(aspect, y_axis.GetAspect());
+ }
+ x_axis.SetAspect(aspect);
+ y_axis.SetAspect(aspect);
+ }
}
- plot.XAxis.Constrain();
- if (axis_equal && !gp.FitY[0])
- plot.YAxis[0].SetAspect(plot.XAxis.GetAspect());
}
- for (int i = 0; i < IMPLOT_Y_AXES; i++) {
- if (gp.FitY[i]) {
- const double ext_size = gp.ExtentsY[i].Size() * 0.5;
- gp.ExtentsY[i].Min -= ext_size * gp.Style.FitPadding.y;
- gp.ExtentsY[i].Max += ext_size * gp.Style.FitPadding.y;
- if (!plot.YAxis[i].IsLockedMin() && !ImNanOrInf(gp.ExtentsY[i].Min))
- plot.YAxis[i].Range.Min = (gp.ExtentsY[i].Min);
- if (!plot.YAxis[i].IsLockedMax() && !ImNanOrInf(gp.ExtentsY[i].Max))
- plot.YAxis[i].Range.Max = (gp.ExtentsY[i].Max);
- if (ImAlmostEqual(plot.YAxis[i].Range.Max, plot.YAxis[i].Range.Min)) {
- plot.YAxis[i].Range.Max += 0.5;
- plot.YAxis[i].Range.Min -= 0.5;
+ for (int i = 0; i < IMPLOT_NUM_Y_AXES; i++) {
+ ImPlotAxis& y_axis = plot.YAxis(i);
+ if (y_axis.FitThisFrame) {
+ y_axis.ApplyFit(gp.Style.FitPadding.y);
+ if (axis_equal && y_axis.OrthoAxis != NULL) {
+ double aspect = y_axis.GetAspect();
+ ImPlotAxis& x_axis = *y_axis.OrthoAxis;
+ if (x_axis.FitThisFrame) {
+ x_axis.ApplyFit(gp.Style.FitPadding.x);
+ x_axis.FitThisFrame = false;
+ aspect = ImMax(x_axis.GetAspect(), aspect);
+ }
+ x_axis.SetAspect(aspect);
+ y_axis.SetAspect(aspect);
}
- plot.YAxis[i].Constrain();
- if (i == 0 && axis_equal && !gp.FitX)
- plot.XAxis.SetAspect(plot.YAxis[0].GetAspect());
}
}
- if (axis_equal && gp.FitX && gp.FitY[0]) {
- double aspect = ImMax(plot.XAxis.GetAspect(), plot.YAxis[0].GetAspect());
- plot.XAxis.SetAspect(aspect);
- plot.YAxis[0].SetAspect(aspect);
- }
+ plot.FitThisFrame = false;
}
// CONTEXT MENUS -----------------------------------------------------------
+ ImGui::PushOverrideID(plot.ID);
+
+ const bool can_ctx = gp.OpenContextThisFrame &&
+ !ImHasFlag(plot.Flags, ImPlotFlags_NoMenus) &&
+ !plot.Items.Legend.Hovered;
+
+
+
// main ctx menu
- if (!ImHasFlag(plot.Flags, ImPlotFlags_NoMenus) && plot.PlotHovered && IO.MouseReleased[gp.InputMap.ContextMenuButton] && !plot.LegendHovered && !plot.ContextLocked)
+ if (can_ctx && plot.Hovered)
ImGui::OpenPopup("##PlotContext");
if (ImGui::BeginPopup("##PlotContext")) {
ShowPlotContextMenu(plot);
ImGui::EndPopup();
}
- // x-axis ctx menu
- if (!ImHasFlag(plot.Flags, ImPlotFlags_NoMenus) && plot.FrameHovered && plot.XAxis.ExtHovered && IO.MouseReleased[gp.InputMap.ContextMenuButton] && !plot.LegendHovered && !plot.ContextLocked)
- ImGui::OpenPopup("##XContext");
- if (ImGui::BeginPopup("##XContext")) {
- ImGui::Text("X-Axis"); ImGui::Separator();
- ShowAxisContextMenu(plot.XAxis, ImHasFlag(plot.Flags, ImPlotFlags_Equal) ? &plot.YAxis[0] : NULL, true);
- ImGui::EndPopup();
+ // axes ctx menus
+ for (int i = 0; i < IMPLOT_NUM_X_AXES; ++i) {
+ ImGui::PushID(i);
+ ImPlotAxis& x_axis = plot.XAxis(i);
+ if (can_ctx && x_axis.Hovered && x_axis.HasMenus())
+ ImGui::OpenPopup("##XContext");
+ if (ImGui::BeginPopup("##XContext")) {
+ ImGui::Text(x_axis.HasLabel() ? plot.GetAxisLabel(x_axis) : i == 0 ? "X-Axis" : "X-Axis %d", i + 1);
+ ImGui::Separator();
+ ShowAxisContextMenu(x_axis, axis_equal ? x_axis.OrthoAxis : NULL, true);
+ ImGui::EndPopup();
+ }
+ ImGui::PopID();
}
-
- // y-axes ctx menus
- for (int i = 0; i < IMPLOT_Y_AXES; ++i) {
+ for (int i = 0; i < IMPLOT_NUM_Y_AXES; ++i) {
ImGui::PushID(i);
- if (!ImHasFlag(plot.Flags, ImPlotFlags_NoMenus) && plot.FrameHovered && plot.YAxis[i].ExtHovered && IO.MouseReleased[gp.InputMap.ContextMenuButton] && !plot.LegendHovered && !plot.ContextLocked)
+ ImPlotAxis& y_axis = plot.YAxis(i);
+ if (can_ctx && y_axis.Hovered && y_axis.HasMenus())
ImGui::OpenPopup("##YContext");
if (ImGui::BeginPopup("##YContext")) {
- if (i == 0) {
- ImGui::Text("Y-Axis"); ImGui::Separator();
- }
- else {
- ImGui::Text("Y-Axis %d", i + 1); ImGui::Separator();
- }
- ShowAxisContextMenu(plot.YAxis[i], (i == 0 && ImHasFlag(plot.Flags, ImPlotFlags_Equal)) ? &plot.XAxis : NULL, false);
+ ImGui::Text(y_axis.HasLabel() ? plot.GetAxisLabel(y_axis) : i == 0 ? "Y-Axis" : "Y-Axis %d", i + 1);
+ ImGui::Separator();
+ ShowAxisContextMenu(y_axis, axis_equal ? y_axis.OrthoAxis : NULL, false);
ImGui::EndPopup();
}
ImGui::PopID();
}
-
+ ImGui::PopID();
// LINKED AXES ------------------------------------------------------------
- PushLinkedAxis(plot.XAxis);
- for (int i = 0; i < IMPLOT_Y_AXES; ++i)
- PushLinkedAxis(plot.YAxis[i]);
+ for (int i = 0; i < ImAxis_COUNT; ++i)
+ plot.Axes[i].PushLinks();
- // CLEANUP ----------------------------------------------------------------
-
- // resset context locked flag
- if (plot.ContextLocked && IO.MouseReleased[gp.InputMap.BoxSelectButton])
- plot.ContextLocked = false;
+ // CLEANUP ----------------------------------------------------------------
+ // remove items
+ if (gp.CurrentItems == &plot.Items)
+ gp.CurrentItems = NULL;
// reset the plot items for the next frame
- for (int i = 0; i < plot.Items.GetSize(); ++i) {
- plot.Items.GetByIndex(i)->SeenThisFrame = false;
+ for (int i = 0; i < plot.Items.GetItemCount(); ++i) {
+ plot.Items.GetItemByIndex(i)->SeenThisFrame = false;
}
// mark the plot as initialized, i.e. having made it through one frame completely
plot.Initialized = true;
-
// Pop ImGui::PushID at the end of BeginPlot
ImGui::PopID();
// Reset context for next plot
- Reset(GImPlot);
+ ResetCtxForNextPlot(GImPlot);
+
+ // setup next subplot
+ if (gp.CurrentSubplot != NULL) {
+ ImGui::PopID();
+ SubplotNextCell();
+ }
}
//-----------------------------------------------------------------------------
-// MISC API
+// BEGIN/END SUBPLOT
//-----------------------------------------------------------------------------
-ImPlotInputMap& GetInputMap() {
- return GImPlot->InputMap;
-}
+static const float SUBPLOT_BORDER_SIZE = 1.0f;
+static const float SUBPLOT_SPLITTER_HALF_THICKNESS = 4.0f;
+static const float SUBPLOT_SPLITTER_FEEDBACK_TIMER = 0.06f;
-void SetNextPlotLimits(double x_min, double x_max, double y_min, double y_max, ImGuiCond cond) {
- IM_ASSERT_USER_ERROR(GImPlot->CurrentPlot == NULL, "SetNextPlotLimits() needs to be called before BeginPlot()!");
- SetNextPlotLimitsX(x_min, x_max, cond);
- SetNextPlotLimitsY(y_min, y_max, cond);
-}
+void SubplotSetCell(int row, int col) {
+ ImPlotContext& gp = *GImPlot;
+ ImPlotSubplot& subplot = *gp.CurrentSubplot;
+ if (row >= subplot.Rows || col >= subplot.Cols)
+ return;
+ float xoff = 0;
+ float yoff = 0;
+ for (int c = 0; c < col; ++c)
+ xoff += subplot.ColRatios[c];
+ for (int r = 0; r < row; ++r)
+ yoff += subplot.RowRatios[r];
+ const ImVec2 grid_size = subplot.GridRect.GetSize();
+ ImVec2 cpos = subplot.GridRect.Min + ImVec2(xoff*grid_size.x,yoff*grid_size.y);
+ cpos.x = IM_ROUND(cpos.x);
+ cpos.y = IM_ROUND(cpos.y);
+ ImGui::GetCurrentWindow()->DC.CursorPos = cpos;
+ // set cell size
+ subplot.CellSize.x = IM_ROUND(subplot.GridRect.GetWidth() * subplot.ColRatios[col]);
+ subplot.CellSize.y = IM_ROUND(subplot.GridRect.GetHeight() * subplot.RowRatios[row]);
+ // setup links
+ const bool lx = ImHasFlag(subplot.Flags, ImPlotSubplotFlags_LinkAllX);
+ const bool ly = ImHasFlag(subplot.Flags, ImPlotSubplotFlags_LinkAllY);
+ const bool lr = ImHasFlag(subplot.Flags, ImPlotSubplotFlags_LinkRows);
+ const bool lc = ImHasFlag(subplot.Flags, ImPlotSubplotFlags_LinkCols);
-void SetNextPlotLimitsX(double x_min, double x_max, ImGuiCond cond) {
- ImPlotContext& gp = *GImPlot;
- IM_ASSERT_USER_ERROR(gp.CurrentPlot == NULL, "SetNextPlotLSetNextPlotLimitsXimitsY() needs to be called before BeginPlot()!");
- 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;
- gp.NextPlotData.XRange.Min = x_min;
- gp.NextPlotData.XRange.Max = x_max;
+ SetNextAxisLinks(ImAxis_X1, lx ? &subplot.ColLinkData[0].Min : lc ? &subplot.ColLinkData[col].Min : NULL,
+ lx ? &subplot.ColLinkData[0].Max : lc ? &subplot.ColLinkData[col].Max : NULL);
+ SetNextAxisLinks(ImAxis_Y1, ly ? &subplot.RowLinkData[0].Min : lr ? &subplot.RowLinkData[row].Min : NULL,
+ ly ? &subplot.RowLinkData[0].Max : lr ? &subplot.RowLinkData[row].Max : NULL);
+ // setup alignment
+ if (!ImHasFlag(subplot.Flags, ImPlotSubplotFlags_NoAlign)) {
+ gp.CurrentAlignmentH = &subplot.RowAlignmentData[row];
+ gp.CurrentAlignmentV = &subplot.ColAlignmentData[col];
+ }
+ // set idx
+ if (ImHasFlag(subplot.Flags, ImPlotSubplotFlags_ColMajor))
+ subplot.CurrentIdx = col * subplot.Rows + row;
+ else
+ subplot.CurrentIdx = row * subplot.Cols + col;
}
-void SetNextPlotLimitsY(double y_min, double y_max, ImGuiCond cond, ImPlotYAxis y_axis) {
- ImPlotContext& gp = *GImPlot;
- 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");
- IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
- gp.NextPlotData.HasYRange[y_axis] = true;
- gp.NextPlotData.YRangeCond[y_axis] = cond;
- gp.NextPlotData.YRange[y_axis].Min = y_min;
- gp.NextPlotData.YRange[y_axis].Max = y_max;
+void SubplotSetCell(int idx) {
+ ImPlotContext& gp = *GImPlot;
+ ImPlotSubplot& subplot = *gp.CurrentSubplot;
+ if (idx >= subplot.Rows * subplot.Cols)
+ return;
+ int row = 0, col = 0;
+ if (ImHasFlag(subplot.Flags, ImPlotSubplotFlags_ColMajor)) {
+ row = idx % subplot.Rows;
+ col = idx / subplot.Rows;
+ }
+ else {
+ row = idx / subplot.Cols;
+ col = idx % subplot.Cols;
+ }
+ return SubplotSetCell(row, col);
}
-void LinkNextPlotLimits(double* xmin, double* xmax, double* ymin, double* ymax, double* ymin2, double* ymax2, double* ymin3, double* ymax3) {
- ImPlotContext& gp = *GImPlot;
- gp.NextPlotData.LinkedXmin = xmin;
- gp.NextPlotData.LinkedXmax = xmax;
- gp.NextPlotData.LinkedYmin[0] = ymin;
- gp.NextPlotData.LinkedYmax[0] = ymax;
- gp.NextPlotData.LinkedYmin[1] = ymin2;
- gp.NextPlotData.LinkedYmax[1] = ymax2;
- gp.NextPlotData.LinkedYmin[2] = ymin3;
- gp.NextPlotData.LinkedYmax[2] = ymax3;
+void SubplotNextCell() {
+ ImPlotContext& gp = *GImPlot;
+ ImPlotSubplot& subplot = *gp.CurrentSubplot;
+ SubplotSetCell(++subplot.CurrentIdx);
}
-void FitNextPlotAxes(bool x, bool y, bool y2, bool y3) {
+bool BeginSubplots(const char* title, int rows, int cols, const ImVec2& size, ImPlotSubplotFlags flags, float* row_sizes, float* col_sizes) {
+ IM_ASSERT_USER_ERROR(rows > 0 && cols > 0, "Invalid sizing arguments!");
+ IM_ASSERT_USER_ERROR(GImPlot != NULL, "No current context. Did you call ImPlot::CreateContext() or ImPlot::SetCurrentContext()?");
+ IM_ASSERT_USER_ERROR(GImPlot->CurrentSubplot == NULL, "Mismatched BeginSubplots()/EndSubplots()!");
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;
+ ImGuiContext &G = *GImGui;
+ ImGuiWindow * Window = G.CurrentWindow;
+ if (Window->SkipItems)
+ return false;
+ const ImGuiID ID = Window->GetID(title);
+ bool just_created = gp.Subplots.GetByKey(ID) == NULL;
+ gp.CurrentSubplot = gp.Subplots.GetOrAddByKey(ID);
+ ImPlotSubplot& subplot = *gp.CurrentSubplot;
+ subplot.ID = ID;
+ subplot.Items.ID = ID - 1;
+ subplot.HasTitle = ImGui::FindRenderedTextEnd(title, NULL) != title;
+ // push ID
+ ImGui::PushID(ID);
+
+ if (just_created)
+ subplot.Flags = flags;
+ else if (flags != subplot.PreviousFlags)
+ subplot.Flags = flags;
+ subplot.PreviousFlags = flags;
+
+ // check for change in rows and cols
+ if (subplot.Rows != rows || subplot.Cols != cols) {
+ subplot.RowAlignmentData.resize(rows);
+ subplot.RowLinkData.resize(rows);
+ subplot.RowRatios.resize(rows);
+ for (int r = 0; r < rows; ++r) {
+ subplot.RowAlignmentData[r].Reset();
+ subplot.RowLinkData[r] = ImPlotRange(0,1);
+ subplot.RowRatios[r] = 1.0f / rows;
+ }
+ subplot.ColAlignmentData.resize(cols);
+ subplot.ColLinkData.resize(cols);
+ subplot.ColRatios.resize(cols);
+ for (int c = 0; c < cols; ++c) {
+ subplot.ColAlignmentData[c].Reset();
+ subplot.ColLinkData[c] = ImPlotRange(0,1);
+ subplot.ColRatios[c] = 1.0f / cols;
+ }
+ }
+ // check incoming size requests
+ float row_sum = 0, col_sum = 0;
+ if (row_sizes != NULL) {
+ row_sum = ImSum(row_sizes, rows);
+ for (int r = 0; r < rows; ++r)
+ subplot.RowRatios[r] = row_sizes[r] / row_sum;
+ }
+ if (col_sizes != NULL) {
+ col_sum = ImSum(col_sizes, cols);
+ for (int c = 0; c < cols; ++c)
+ subplot.ColRatios[c] = col_sizes[c] / col_sum;
+ }
+ subplot.Rows = rows;
+ subplot.Cols = cols;
+
+ // calc plot frame sizes
+ ImVec2 title_size(0.0f, 0.0f);
+ if (!ImHasFlag(subplot.Flags, ImPlotSubplotFlags_NoTitle))
+ title_size = ImGui::CalcTextSize(title, NULL, true);
+ const float pad_top = title_size.x > 0.0f ? title_size.y + gp.Style.LabelPadding.y : 0;
+ const ImVec2 half_pad = gp.Style.PlotPadding/2;
+ const ImVec2 frame_size = ImGui::CalcItemSize(size, gp.Style.PlotDefaultSize.x, gp.Style.PlotDefaultSize.y);
+ subplot.FrameRect = ImRect(Window->DC.CursorPos, Window->DC.CursorPos + frame_size);
+ subplot.GridRect.Min = subplot.FrameRect.Min + half_pad + ImVec2(0,pad_top);
+ subplot.GridRect.Max = subplot.FrameRect.Max - half_pad;
+ subplot.FrameHovered = subplot.FrameRect.Contains(ImGui::GetMousePos()) && ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows);
+
+ // outside legend adjustments (TODO: make function)
+ const bool share_items = ImHasFlag(subplot.Flags, ImPlotSubplotFlags_ShareItems);
+ if (share_items)
+ gp.CurrentItems = &subplot.Items;
+ if (share_items && !ImHasFlag(subplot.Flags, ImPlotSubplotFlags_NoLegend) && subplot.Items.GetLegendCount() > 0) {
+ ImPlotLegend& legend = subplot.Items.Legend;
+ const bool horz = ImHasFlag(legend.Flags, ImPlotLegendFlags_Horizontal);
+ const ImVec2 legend_size = CalcLegendSize(subplot.Items, gp.Style.LegendInnerPadding, gp.Style.LegendSpacing, !horz);
+ const bool west = ImHasFlag(legend.Location, ImPlotLocation_West) && !ImHasFlag(legend.Location, ImPlotLocation_East);
+ const bool east = ImHasFlag(legend.Location, ImPlotLocation_East) && !ImHasFlag(legend.Location, ImPlotLocation_West);
+ const bool north = ImHasFlag(legend.Location, ImPlotLocation_North) && !ImHasFlag(legend.Location, ImPlotLocation_South);
+ const bool south = ImHasFlag(legend.Location, ImPlotLocation_South) && !ImHasFlag(legend.Location, ImPlotLocation_North);
+ if ((west && !horz) || (west && horz && !north && !south))
+ subplot.GridRect.Min.x += (legend_size.x + gp.Style.LegendPadding.x);
+ if ((east && !horz) || (east && horz && !north && !south))
+ subplot.GridRect.Max.x -= (legend_size.x + gp.Style.LegendPadding.x);
+ if ((north && horz) || (north && !horz && !west && !east))
+ subplot.GridRect.Min.y += (legend_size.y + gp.Style.LegendPadding.y);
+ if ((south && horz) || (south && !horz && !west && !east))
+ subplot.GridRect.Max.y -= (legend_size.y + gp.Style.LegendPadding.y);
+ }
+
+ // render single background frame
+ ImGui::RenderFrame(subplot.FrameRect.Min, subplot.FrameRect.Max, GetStyleColorU32(ImPlotCol_FrameBg), true, ImGui::GetStyle().FrameRounding);
+ // render title
+ if (title_size.x > 0.0f && !ImHasFlag(subplot.Flags, ImPlotFlags_NoTitle)) {
+ const ImU32 col = GetStyleColorU32(ImPlotCol_TitleText);
+ AddTextCentered(ImGui::GetWindowDrawList(),ImVec2(subplot.GridRect.GetCenter().x, subplot.GridRect.Min.y - pad_top + half_pad.y),col,title);
+ }
+
+ // render splitters
+ if (!ImHasFlag(subplot.Flags, ImPlotSubplotFlags_NoResize)) {
+ ImDrawList& DrawList = *ImGui::GetWindowDrawList();
+ const ImU32 hov_col = ImGui::ColorConvertFloat4ToU32(GImGui->Style.Colors[ImGuiCol_SeparatorHovered]);
+ const ImU32 act_col = ImGui::ColorConvertFloat4ToU32(GImGui->Style.Colors[ImGuiCol_SeparatorActive]);
+ float xpos = subplot.GridRect.Min.x;
+ float ypos = subplot.GridRect.Min.y;
+ int separator = 1;
+ // bool pass = false;
+ for (int r = 0; r < subplot.Rows-1; ++r) {
+ ypos += subplot.RowRatios[r] * subplot.GridRect.GetHeight();
+ const ImGuiID sep_id = subplot.ID + separator;
+ ImGui::KeepAliveID(sep_id);
+ const ImRect sep_bb = ImRect(subplot.GridRect.Min.x, ypos-SUBPLOT_SPLITTER_HALF_THICKNESS, subplot.GridRect.Max.x, ypos+SUBPLOT_SPLITTER_HALF_THICKNESS);
+ bool sep_hov = false, sep_hld = false;
+ const bool sep_clk = ImGui::ButtonBehavior(sep_bb, sep_id, &sep_hov, &sep_hld, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_AllowItemOverlap | ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_PressedOnDoubleClick);
+ if ((sep_hov && G.HoveredIdTimer > SUBPLOT_SPLITTER_FEEDBACK_TIMER) || sep_hld) {
+ if (sep_clk && ImGui::IsMouseDoubleClicked(0)) {
+ float p = (subplot.RowRatios[r] + subplot.RowRatios[r+1])/2;
+ subplot.RowRatios[r] = subplot.RowRatios[r+1] = p;
+ }
+ if (sep_clk) {
+ subplot.TempSizes[0] = subplot.RowRatios[r];
+ subplot.TempSizes[1] = subplot.RowRatios[r+1];
+ }
+ if (sep_hld) {
+ float dp = ImGui::GetMouseDragDelta(0).y / subplot.GridRect.GetHeight();
+ if (subplot.TempSizes[0] + dp > 0.1f && subplot.TempSizes[1] - dp > 0.1f) {
+ subplot.RowRatios[r] = subplot.TempSizes[0] + dp;
+ subplot.RowRatios[r+1] = subplot.TempSizes[1] - dp;
+ }
+ }
+ DrawList.AddLine(ImVec2(IM_ROUND(subplot.GridRect.Min.x),IM_ROUND(ypos)),
+ ImVec2(IM_ROUND(subplot.GridRect.Max.x),IM_ROUND(ypos)),
+ sep_hld ? act_col : hov_col, SUBPLOT_BORDER_SIZE);
+ ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeNS);
+ }
+ separator++;
+ }
+ for (int c = 0; c < subplot.Cols-1; ++c) {
+ xpos += subplot.ColRatios[c] * subplot.GridRect.GetWidth();
+ const ImGuiID sep_id = subplot.ID + separator;
+ ImGui::KeepAliveID(sep_id);
+ const ImRect sep_bb = ImRect(xpos-SUBPLOT_SPLITTER_HALF_THICKNESS, subplot.GridRect.Min.y, xpos+SUBPLOT_SPLITTER_HALF_THICKNESS, subplot.GridRect.Max.y);
+ bool sep_hov = false, sep_hld = false;
+ const bool sep_clk = ImGui::ButtonBehavior(sep_bb, sep_id, &sep_hov, &sep_hld, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_AllowItemOverlap | ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_PressedOnDoubleClick);
+ if ((sep_hov && G.HoveredIdTimer > SUBPLOT_SPLITTER_FEEDBACK_TIMER) || sep_hld) {
+ if (sep_clk && ImGui::IsMouseDoubleClicked(0)) {
+ float p = (subplot.ColRatios[c] + subplot.ColRatios[c+1])/2;
+ subplot.ColRatios[c] = subplot.ColRatios[c+1] = p;
+ }
+ if (sep_clk) {
+ subplot.TempSizes[0] = subplot.ColRatios[c];
+ subplot.TempSizes[1] = subplot.ColRatios[c+1];
+ }
+ if (sep_hld) {
+ float dp = ImGui::GetMouseDragDelta(0).x / subplot.GridRect.GetWidth();
+ if (subplot.TempSizes[0] + dp > 0.1f && subplot.TempSizes[1] - dp > 0.1f) {
+ subplot.ColRatios[c] = subplot.TempSizes[0] + dp;
+ subplot.ColRatios[c+1] = subplot.TempSizes[1] - dp;
+ }
+ }
+ DrawList.AddLine(ImVec2(IM_ROUND(xpos),IM_ROUND(subplot.GridRect.Min.y)),
+ ImVec2(IM_ROUND(xpos),IM_ROUND(subplot.GridRect.Max.y)),
+ sep_hld ? act_col : hov_col, SUBPLOT_BORDER_SIZE);
+ ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeEW);
+ }
+ separator++;
+ }
+ }
+
+ // set outgoing sizes
+ if (row_sizes != NULL) {
+ for (int r = 0; r < rows; ++r)
+ row_sizes[r] = subplot.RowRatios[r] * row_sum;
+ }
+ if (col_sizes != NULL) {
+ for (int c = 0; c < cols; ++c)
+ col_sizes[c] = subplot.ColRatios[c] * col_sum;
+ }
+
+ // push styling
+ PushStyleColor(ImPlotCol_FrameBg, IM_COL32_BLACK_TRANS);
+ PushStyleVar(ImPlotStyleVar_PlotPadding, half_pad);
+ PushStyleVar(ImPlotStyleVar_PlotMinSize, ImVec2(0,0));
+ ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize,0);
+
+ // set initial cursor pos
+ Window->DC.CursorPos = subplot.GridRect.Min;
+ // begin alignments
+ for (int r = 0; r < subplot.Rows; ++r)
+ subplot.RowAlignmentData[r].Begin();
+ for (int c = 0; c < subplot.Cols; ++c)
+ subplot.ColAlignmentData[c].Begin();
+ // clear legend data
+ subplot.Items.Legend.Reset();
+ // Setup first subplot
+ SubplotSetCell(0,0);
+ return true;
}
-void SetNextPlotTicksX(const double* values, int n_ticks, const char* const labels[], bool show_default) {
+void EndSubplots() {
+ IM_ASSERT_USER_ERROR(GImPlot != NULL, "No current context. Did you call ImPlot::CreateContext() or ImPlot::SetCurrentContext()?");
+ IM_ASSERT_USER_ERROR(GImPlot->CurrentSubplot != NULL, "Mismatched BeginSubplots()/EndSubplots()!");
ImPlotContext& gp = *GImPlot;
- IM_ASSERT_USER_ERROR(gp.CurrentPlot == NULL, "SetNextPlotTicksX() needs to be called before BeginPlot()!");
- gp.NextPlotData.ShowDefaultTicksX = show_default;
- AddTicksCustom(values, labels, n_ticks, gp.XTicks, GetFormatX());
-}
+ ImPlotSubplot& subplot = *GImPlot->CurrentSubplot;
+ // set alignments
+ for (int r = 0; r < subplot.Rows; ++r)
+ subplot.RowAlignmentData[r].End();
+ for (int c = 0; c < subplot.Cols; ++c)
+ subplot.ColAlignmentData[c].End();
+ // pop styling
+ PopStyleColor();
+ PopStyleVar();
+ PopStyleVar();
+ ImGui::PopStyleVar();
+ // legend
+ subplot.Items.Legend.Hovered = false;
+ for (int i = 0; i < subplot.Items.GetItemCount(); ++i)
+ subplot.Items.GetItemByIndex(i)->LegendHovered = false;
+ // render legend
+ const bool share_items = ImHasFlag(subplot.Flags, ImPlotSubplotFlags_ShareItems);
+ ImDrawList& DrawList = *ImGui::GetWindowDrawList();
+ if (share_items && !ImHasFlag(subplot.Flags, ImPlotSubplotFlags_NoLegend) && subplot.Items.GetLegendCount() > 0) {
+ const bool legend_horz = ImHasFlag(subplot.Items.Legend.Flags, ImPlotLegendFlags_Horizontal);
+ const ImVec2 legend_size = CalcLegendSize(subplot.Items, gp.Style.LegendInnerPadding, gp.Style.LegendSpacing, !legend_horz);
+ const ImVec2 legend_pos = GetLocationPos(subplot.FrameRect, legend_size, subplot.Items.Legend.Location, gp.Style.PlotPadding);
+ subplot.Items.Legend.Rect = ImRect(legend_pos, legend_pos + legend_size);
+ subplot.Items.Legend.Hovered = subplot.FrameHovered && subplot.Items.Legend.Rect.Contains(ImGui::GetIO().MousePos);
+ ImGui::PushClipRect(subplot.FrameRect.Min, subplot.FrameRect.Max, true);
+ ImU32 col_bg = GetStyleColorU32(ImPlotCol_LegendBg);
+ ImU32 col_bd = GetStyleColorU32(ImPlotCol_LegendBorder);
+ DrawList.AddRectFilled(subplot.Items.Legend.Rect.Min, subplot.Items.Legend.Rect.Max, col_bg);
+ DrawList.AddRect(subplot.Items.Legend.Rect.Min, subplot.Items.Legend.Rect.Max, col_bd);
+ bool legend_contextable = ShowLegendEntries(subplot.Items, subplot.Items.Legend.Rect, subplot.Items.Legend.Hovered, gp.Style.LegendInnerPadding, gp.Style.LegendSpacing, !legend_horz, DrawList)
+ && !ImHasFlag(subplot.Items.Legend.Flags, ImPlotLegendFlags_NoMenus);
+ if (legend_contextable && !ImHasFlag(subplot.Flags, ImPlotSubplotFlags_NoMenus) && ImGui::GetIO().MouseReleased[gp.InputMap.Menu])
+ ImGui::OpenPopup("##LegendContext");
+ ImGui::PopClipRect();
+ if (ImGui::BeginPopup("##LegendContext")) {
+ ImGui::Text("Legend"); ImGui::Separator();
+ if (ShowLegendContextMenu(subplot.Items.Legend, !ImHasFlag(subplot.Flags, ImPlotFlags_NoLegend)))
+ ImFlipFlag(subplot.Flags, ImPlotFlags_NoLegend);
+ ImGui::EndPopup();
+ }
+ }
+ else {
+ subplot.Items.Legend.Rect = ImRect();
+ }
+ // remove items
+ if (gp.CurrentItems == &subplot.Items)
+ gp.CurrentItems = NULL;
+ // reset the plot items for the next frame (TODO: put this elswhere)
+ for (int i = 0; i < subplot.Items.GetItemCount(); ++i) {
+ subplot.Items.GetItemByIndex(i)->SeenThisFrame = false;
+ }
+ // pop id
+ ImGui::PopID();
+ // set DC back correctly
+ GImGui->CurrentWindow->DC.CursorPos = subplot.FrameRect.Min;
+ ImGui::Dummy(subplot.FrameRect.GetSize());
+ ResetCtxForNextSubplot(GImPlot);
-void SetNextPlotTicksX(double x_min, double x_max, int n_ticks, const char* const 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* const labels[], bool show_default, ImPlotYAxis y_axis) {
+//-----------------------------------------------------------------------------
+// [SECTION] Plot Utils
+//-----------------------------------------------------------------------------
+
+void SetAxis(ImAxis axis) {
ImPlotContext& gp = *GImPlot;
- IM_ASSERT_USER_ERROR(gp.CurrentPlot == NULL, "SetNextPlotTicksY() needs to be called before BeginPlot()!");
- IM_ASSERT_USER_ERROR(y_axis >= 0 && y_axis < IMPLOT_Y_AXES, "y_axis needs to be between 0 and IMPLOT_Y_AXES");
- gp.NextPlotData.ShowDefaultTicksY[y_axis] = show_default;
- AddTicksCustom(values, labels, n_ticks, gp.YTicks[y_axis], GetFormatY(y_axis));
+ IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "SetAxis() needs to be called between BeginPlot() and EndPlot()!");
+ IM_ASSERT_USER_ERROR(axis >= ImAxis_X1 && axis < ImAxis_COUNT, "Axis index out of bounds!");
+ IM_ASSERT_USER_ERROR(gp.CurrentPlot->Axes[axis].Enabled, "Axis is not enabled! Did you forget to call SetupAxis()?");
+ SetupLock();
+ if (axis < ImAxis_Y1)
+ gp.CurrentPlot->CurrentX = axis;
+ else
+ gp.CurrentPlot->CurrentY = axis;
}
-void SetNextPlotTicksY(double y_min, double y_max, int n_ticks, const char* const labels[], bool show_default, ImPlotYAxis 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);
+void SetAxes(ImAxis x_idx, ImAxis y_idx) {
+ ImPlotContext& gp = *GImPlot;
+ IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "SetAxes() needs to be called between BeginPlot() and EndPlot()!");
+ IM_ASSERT_USER_ERROR(x_idx >= ImAxis_X1 && x_idx < ImAxis_Y1, "X-Axis index out of bounds!");
+ IM_ASSERT_USER_ERROR(y_idx >= ImAxis_Y1 && y_idx < ImAxis_COUNT, "Y-Axis index out of bounds!");
+ IM_ASSERT_USER_ERROR(gp.CurrentPlot->Axes[x_idx].Enabled, "Axis is not enabled! Did you forget to call SetupAxis()?");
+ IM_ASSERT_USER_ERROR(gp.CurrentPlot->Axes[y_idx].Enabled, "Axis is not enabled! Did you forget to call SetupAxis()?");
+ SetupLock();
+ gp.CurrentPlot->CurrentX = x_idx;
+ gp.CurrentPlot->CurrentY = y_idx;
}
-void SetNextPlotFormatX(const char* fmt){
+ImPlotPoint PixelsToPlot(float x, float y, ImAxis x_idx, ImAxis y_idx) {
ImPlotContext& gp = *GImPlot;
- IM_ASSERT_USER_ERROR(gp.CurrentPlot == NULL, "SetNextPlotFormatX() needs to be called before BeginPlot()!");
- gp.NextPlotData.HasFmtX = true;
- ImStrncpy(gp.NextPlotData.FmtX, fmt, 16);
+ IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "PixelsToPlot() needs to be called between BeginPlot() and EndPlot()!");
+ IM_ASSERT_USER_ERROR(x_idx == IMPLOT_AUTO || (x_idx >= ImAxis_X1 && x_idx < ImAxis_Y1), "X-Axis index out of bounds!");
+ IM_ASSERT_USER_ERROR(y_idx == IMPLOT_AUTO || (y_idx >= ImAxis_Y1 && y_idx < ImAxis_COUNT), "Y-Axis index out of bounds!");
+ SetupLock();
+ ImPlotPlot& plot = *gp.CurrentPlot;
+ ImPlotAxis& x_axis = x_idx == IMPLOT_AUTO ? plot.Axes[plot.CurrentX] : plot.Axes[x_idx];
+ ImPlotAxis& y_axis = y_idx == IMPLOT_AUTO ? plot.Axes[plot.CurrentY] : plot.Axes[y_idx];
+ return ImPlotPoint( x_axis.PixelsToPlot(x), y_axis.PixelsToPlot(y) );
}
-void SetNextPlotFormatY(const char* fmt, ImPlotYAxis y_axis) {
- ImPlotContext& gp = *GImPlot;
- IM_ASSERT_USER_ERROR(gp.CurrentPlot == NULL, "SetNextPlotFormatY() needs to be called before BeginPlot()!");
- IM_ASSERT_USER_ERROR(y_axis >= 0 && y_axis < IMPLOT_Y_AXES, "y_axis needs to be between 0 and IMPLOT_Y_AXES");
- gp.NextPlotData.HasFmtY[y_axis] = true;
- ImStrncpy(gp.NextPlotData.FmtY[y_axis], fmt, 16);
+ImPlotPoint PixelsToPlot(const ImVec2& pix, ImAxis x_idx, ImAxis y_idx) {
+ return PixelsToPlot(pix.x, pix.y, x_idx, y_idx);
}
-void SetPlotYAxis(ImPlotYAxis y_axis) {
+ImVec2 PlotToPixels(double x, double y, ImAxis x_idx, ImAxis y_idx) {
ImPlotContext& gp = *GImPlot;
- 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");
- gp.CurrentPlot->CurrentYAxis = y_axis;
+ IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "PlotToPixels() needs to be called between BeginPlot() and EndPlot()!");
+ IM_ASSERT_USER_ERROR(x_idx == IMPLOT_AUTO || (x_idx >= ImAxis_X1 && x_idx < ImAxis_Y1), "X-Axis index out of bounds!");
+ IM_ASSERT_USER_ERROR(y_idx == IMPLOT_AUTO || (y_idx >= ImAxis_Y1 && y_idx < ImAxis_COUNT), "Y-Axis index out of bounds!");
+ SetupLock();
+ ImPlotPlot& plot = *gp.CurrentPlot;
+ ImPlotAxis& x_axis = x_idx == IMPLOT_AUTO ? plot.Axes[plot.CurrentX] : plot.Axes[x_idx];
+ ImPlotAxis& y_axis = y_idx == IMPLOT_AUTO ? plot.Axes[plot.CurrentY] : plot.Axes[y_idx];
+ return ImVec2( x_axis.PlotToPixels(x), y_axis.PlotToPixels(y) );
+}
+
+ImVec2 PlotToPixels(const ImPlotPoint& plt, ImAxis x_idx, ImAxis y_idx) {
+ return PlotToPixels(plt.x, plt.y, x_idx, y_idx);
}
ImVec2 GetPlotPos() {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "GetPlotPos() needs to be called between BeginPlot() and EndPlot()!");
+ SetupLock();
return gp.CurrentPlot->PlotRect.Min;
}
ImVec2 GetPlotSize() {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "GetPlotSize() needs to be called between BeginPlot() and EndPlot()!");
+ SetupLock();
return gp.CurrentPlot->PlotRect.GetSize();
}
-ImDrawList* GetPlotDrawList() {
- return ImGui::GetWindowDrawList();
+ImPlotPoint GetPlotMousePos(ImAxis x_idx, ImAxis y_idx) {
+ IM_ASSERT_USER_ERROR(GImPlot->CurrentPlot != NULL, "GetPlotMousePos() needs to be called between BeginPlot() and EndPlot()!");
+ SetupLock();
+ return PixelsToPlot(ImGui::GetMousePos(), x_idx, y_idx);
}
-void PushPlotClipRect(float expand) {
+ImPlotRect GetPlotLimits(ImAxis x_idx, ImAxis y_idx) {
ImPlotContext& gp = *GImPlot;
- ImRect rect = gp.CurrentPlot->PlotRect;
- rect.Expand(expand);
- IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "PushPlotClipRect() needs to be called between BeginPlot() and EndPlot()!");
- ImGui::PushClipRect(rect.Min, rect.Max, true);
-}
-
-void PopPlotClipRect() {
- ImGui::PopClipRect();
+ IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "GetPlotLimits() needs to be called between BeginPlot() and EndPlot()!");
+ IM_ASSERT_USER_ERROR(x_idx == IMPLOT_AUTO || (x_idx >= ImAxis_X1 && x_idx < ImAxis_Y1), "X-Axis index out of bounds!");
+ IM_ASSERT_USER_ERROR(y_idx == IMPLOT_AUTO || (y_idx >= ImAxis_Y1 && y_idx < ImAxis_COUNT), "Y-Axis index out of bounds!");
+ SetupLock();
+ ImPlotPlot& plot = *gp.CurrentPlot;
+ ImPlotAxis& x_axis = x_idx == IMPLOT_AUTO ? plot.Axes[plot.CurrentX] : plot.Axes[x_idx];
+ ImPlotAxis& y_axis = y_idx == IMPLOT_AUTO ? plot.Axes[plot.CurrentY] : plot.Axes[y_idx];
+ ImPlotRect limits;
+ limits.X = x_axis.Range;
+ limits.Y = y_axis.Range;
+ return limits;
}
bool IsPlotHovered() {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "IsPlotHovered() needs to be called between BeginPlot() and EndPlot()!");
- return gp.CurrentPlot->PlotHovered;
+ SetupLock();
+ return gp.CurrentPlot->Hovered;
}
-bool IsPlotXAxisHovered() {
+bool IsAxisHovered(ImAxis axis) {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "IsPlotXAxisHovered() needs to be called between BeginPlot() and EndPlot()!");
- return gp.CurrentPlot->XAxis.ExtHovered;
+ SetupLock();
+ return gp.CurrentPlot->Axes[axis].Hovered;
}
-bool IsPlotYAxisHovered(ImPlotYAxis y_axis_in) {
+bool IsSubplotsHovered() {
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 ImPlotYAxis y_axis = y_axis_in >= 0 ? y_axis_in : gp.CurrentPlot->CurrentYAxis;
- return gp.CurrentPlot->YAxis[y_axis].ExtHovered;
-}
-
-ImPlotPoint GetPlotMousePos(ImPlotYAxis 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, "GetPlotMousePos() needs to be called between BeginPlot() and EndPlot()!");
- const ImPlotYAxis y_axis = y_axis_in >= 0 ? y_axis_in : gp.CurrentPlot->CurrentYAxis;
- return gp.MousePos[y_axis];
-}
-
-
-ImPlotLimits GetPlotLimits(ImPlotYAxis 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, "GetPlotLimits() needs to be called between BeginPlot() and EndPlot()!");
- const ImPlotYAxis y_axis = y_axis_in >= 0 ? y_axis_in : gp.CurrentPlot->CurrentYAxis;
-
- ImPlotPlot& plot = *gp.CurrentPlot;
- ImPlotLimits limits;
- limits.X = plot.XAxis.Range;
- limits.Y = plot.YAxis[y_axis].Range;
- return limits;
+ IM_ASSERT_USER_ERROR(gp.CurrentSubplot != NULL, "IsSubplotsHovered() needs to be called between BeginSubplots() and EndSubplots()!");
+ return gp.CurrentSubplot->FrameHovered;
}
bool IsPlotSelected() {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "IsPlotSelected() needs to be called between BeginPlot() and EndPlot()!");
+ SetupLock();
return gp.CurrentPlot->Selected;
}
-ImPlotLimits GetPlotSelection(ImPlotYAxis y_axis) {
+ImPlotRect GetPlotSelection(ImAxis x_idx, ImAxis y_idx) {
ImPlotContext& gp = *GImPlot;
- IM_ASSERT_USER_ERROR(y_axis >= -1 && y_axis < IMPLOT_Y_AXES, "y_axis needs to between -1 and IMPLOT_Y_AXES");
IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "GetPlotSelection() needs to be called between BeginPlot() and EndPlot()!");
+ SetupLock();
ImPlotPlot& plot = *gp.CurrentPlot;
- y_axis = y_axis >= 0 ? y_axis : gp.CurrentPlot->CurrentYAxis;
if (!plot.Selected)
- return ImPlotLimits(0,0,0,0);
- UpdateTransformCache();
- ImPlotPoint p1 = PixelsToPlot(plot.SelectRect.Min + plot.PlotRect.Min, y_axis);
- ImPlotPoint p2 = PixelsToPlot(plot.SelectRect.Max + plot.PlotRect.Min, y_axis);
- ImPlotLimits result;
+ return ImPlotRect(0,0,0,0);
+ ImPlotPoint p1 = PixelsToPlot(plot.SelectRect.Min + plot.PlotRect.Min, x_idx, y_idx);
+ ImPlotPoint p2 = PixelsToPlot(plot.SelectRect.Max + plot.PlotRect.Min, x_idx, y_idx);
+ ImPlotRect 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);
@@ -2738,423 +3559,411 @@ ImPlotLimits GetPlotSelection(ImPlotYAxis y_axis) {
return result;
}
-bool IsPlotQueried() {
+void CancelPlotSelection() {
ImPlotContext& gp = *GImPlot;
- IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "IsPlotQueried() needs to be called between BeginPlot() and EndPlot()!");
- return gp.CurrentPlot->Queried;
+ IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "CancelPlotSelection() needs to be called between BeginPlot() and EndPlot()!");
+ SetupLock();
+ ImPlotPlot& plot = *gp.CurrentPlot;
+ if (plot.Selected)
+ plot.Selected = plot.Selecting = false;
}
-ImPlotLimits GetPlotQuery(ImPlotYAxis y_axis) {
+void HideNextItem(bool hidden, ImPlotCond cond) {
ImPlotContext& gp = *GImPlot;
- IM_ASSERT_USER_ERROR(y_axis >= -1 && y_axis < IMPLOT_Y_AXES, "y_axis needs to between -1 and IMPLOT_Y_AXES");
- IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "GetPlotQuery() needs to be called between BeginPlot() and EndPlot()!");
- ImPlotPlot& plot = *gp.CurrentPlot;
- y_axis = y_axis >= 0 ? y_axis : gp.CurrentPlot->CurrentYAxis;
- if (!plot.Queried)
- return ImPlotLimits(0,0,0,0);
- UpdateTransformCache();
- ImPlotPoint p1 = PixelsToPlot(plot.QueryRect.Min + plot.PlotRect.Min, y_axis);
- ImPlotPoint p2 = PixelsToPlot(plot.QueryRect.Max + plot.PlotRect.Min, y_axis);
- 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;
+ gp.NextItemData.HasHidden = true;
+ gp.NextItemData.Hidden = hidden;
+ gp.NextItemData.HiddenCond = cond;
}
-void SetPlotQuery(const ImPlotLimits& query, ImPlotYAxis y_axis) {
+//-----------------------------------------------------------------------------
+// [SECTION] Plot Tools
+//-----------------------------------------------------------------------------
+
+void Annotation(double x, double y, const ImVec4& col, const ImVec2& offset, bool clamp, bool round) {
ImPlotContext& gp = *GImPlot;
- IM_ASSERT_USER_ERROR(y_axis >= -1 && y_axis < IMPLOT_Y_AXES, "y_axis needs to between -1 and IMPLOT_Y_AXES");
- IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "GetPlotQuery() needs to be called between BeginPlot() and EndPlot()!");
- ImPlotPlot& plot = *gp.CurrentPlot;
- y_axis = y_axis >= 0 ? y_axis : gp.CurrentPlot->CurrentYAxis;
- UpdateTransformCache();
- ImVec2 p1 = PlotToPixels(query.Min(),y_axis);
- ImVec2 p2 = PlotToPixels(query.Max(),y_axis);
- plot.Queried = true;
- plot.Querying = false;
- plot.QueryRect = ImRect(ImMin(p1,p2)-plot.PlotRect.Min, ImMax(p1,p2)-plot.PlotRect.Min);
+ IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "Annotation() needs to be called between BeginPlot() and EndPlot()!");
+ SetupLock();
+ char x_buff[IMPLOT_LABEL_MAX_SIZE];
+ char y_buff[IMPLOT_LABEL_MAX_SIZE];
+ ImPlotAxis& x_axis = gp.CurrentPlot->Axes[gp.CurrentPlot->CurrentX];
+ ImPlotAxis& y_axis = gp.CurrentPlot->Axes[gp.CurrentPlot->CurrentX];
+ LabelAxisValue(x_axis, x, x_buff, sizeof(x_buff), round);
+ LabelAxisValue(y_axis, y, y_buff, sizeof(y_buff), round);
+ Annotation(x,y,col,offset,clamp,"%s, %s",x_buff,y_buff);
}
-void AnnotateEx(double x, double y, bool clamp, const ImVec4& col, const ImVec2& off, const char* fmt, va_list args) {
+void AnnotationV(double x, double y, const ImVec4& col, const ImVec2& offset, bool clamp, const char* fmt, va_list args) {
ImPlotContext& gp = *GImPlot;
- IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "Annotate() needs to be called between BeginPlot() and EndPlot()!");
- ImVec2 pos = PlotToPixels(x,y);
+ IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "Annotation() needs to be called between BeginPlot() and EndPlot()!");
+ SetupLock();
+ ImVec2 pos = PlotToPixels(x,y,IMPLOT_AUTO,IMPLOT_AUTO);
ImU32 bg = ImGui::GetColorU32(col);
ImU32 fg = col.w == 0 ? GetStyleColorU32(ImPlotCol_InlayText) : CalcTextColor(col);
- gp.Annotations.AppendV(pos, off, bg, fg, clamp, fmt, args);
-}
-
-void AnnotateV(double x, double y, const ImVec2& offset, const char* fmt, va_list args) {
- AnnotateEx(x,y,false,ImVec4(0,0,0,0),offset,fmt,args);
+ gp.Annotations.AppendV(pos, offset, bg, fg, clamp, fmt, args);
}
-void Annotate(double x, double y, const ImVec2& offset, const char* fmt, ...) {
+void Annotation(double x, double y, const ImVec4& col, const ImVec2& offset, bool clamp, const char* fmt, ...) {
va_list args;
va_start(args, fmt);
- AnnotateV(x,y,offset,fmt,args);
+ AnnotationV(x,y,col,offset,clamp,fmt,args);
va_end(args);
}
-void AnnotateV(double x, double y, const ImVec2& offset, const ImVec4& col, const char* fmt, va_list args) {
- AnnotateEx(x,y,false,col,offset,fmt,args);
+void TagV(ImAxis axis, double v, const ImVec4& col, const char* fmt, va_list args) {
+ ImPlotContext& gp = *GImPlot;
+ SetupLock();
+ ImU32 bg = ImGui::GetColorU32(col);
+ ImU32 fg = col.w == 0 ? GetStyleColorU32(ImPlotCol_AxisText) : CalcTextColor(col);
+ gp.Tags.AppendV(axis,v,bg,fg,fmt,args);
}
-void Annotate(double x, double y, const ImVec2& offset, const ImVec4& col, const char* fmt, ...) {
+void Tag(ImAxis axis, double v, const ImVec4& col, const char* fmt, ...) {
va_list args;
va_start(args, fmt);
- AnnotateV(x,y,offset,col,fmt,args);
+ TagV(axis,v,col,fmt,args);
va_end(args);
}
-void AnnotateClampedV(double x, double y, const ImVec2& offset, const char* fmt, va_list args) {
- AnnotateEx(x,y,true,ImVec4(0,0,0,0),offset,fmt,args);
+void Tag(ImAxis axis, double v, const ImVec4& color, bool round) {
+ ImPlotContext& gp = *GImPlot;
+ SetupLock();
+ char buff[IMPLOT_LABEL_MAX_SIZE];
+ ImPlotAxis& ax = gp.CurrentPlot->Axes[axis];
+ LabelAxisValue(ax, v, buff, sizeof(buff), round);
+ Tag(axis,v,color,"%s",buff);
}
-void AnnotateClamped(double x, double y, const ImVec2& offset, const char* fmt, ...) {
+IMPLOT_API void TagX(double x, const ImVec4& color, bool round) {
+ IM_ASSERT_USER_ERROR(GImPlot->CurrentPlot != NULL, "TagX() needs to be called between BeginPlot() and EndPlot()!");
+ Tag(GImPlot->CurrentPlot->CurrentX, x, color, round);
+}
+
+IMPLOT_API void TagX(double x, const ImVec4& color, const char* fmt, ...) {
+ IM_ASSERT_USER_ERROR(GImPlot->CurrentPlot != NULL, "TagX() needs to be called between BeginPlot() and EndPlot()!");
va_list args;
va_start(args, fmt);
- AnnotateClampedV(x,y,offset,fmt,args);
+ TagV(GImPlot->CurrentPlot->CurrentX,x,color,fmt,args);
va_end(args);
}
-void AnnotateClampedV(double x, double y, const ImVec2& offset, const ImVec4& col, const char* fmt, va_list args) {
- AnnotateEx(x,y,true,col,offset,fmt,args);
+IMPLOT_API void TagXV(double x, const ImVec4& color, const char* fmt, va_list args) {
+ IM_ASSERT_USER_ERROR(GImPlot->CurrentPlot != NULL, "TagX() needs to be called between BeginPlot() and EndPlot()!");
+ TagV(GImPlot->CurrentPlot->CurrentX, x, color, fmt, args);
+}
+
+IMPLOT_API void TagY(double y, const ImVec4& color, bool round) {
+ IM_ASSERT_USER_ERROR(GImPlot->CurrentPlot != NULL, "TagY() needs to be called between BeginPlot() and EndPlot()!");
+ Tag(GImPlot->CurrentPlot->CurrentY, y, color, round);
}
-void AnnotateClamped(double x, double y, const ImVec2& offset, const ImVec4& col, const char* fmt, ...) {
+IMPLOT_API void TagY(double y, const ImVec4& color, const char* fmt, ...) {
+ IM_ASSERT_USER_ERROR(GImPlot->CurrentPlot != NULL, "TagY() needs to be called between BeginPlot() and EndPlot()!");
va_list args;
va_start(args, fmt);
- AnnotateClampedV(x,y,offset,col,fmt,args);
+ TagV(GImPlot->CurrentPlot->CurrentY,y,color,fmt,args);
va_end(args);
}
-bool DragLineX(const char* id, double* value, bool show_label, const ImVec4& col, float thickness) {
+IMPLOT_API void TagYV(double y, const ImVec4& color, const char* fmt, va_list args) {
+ IM_ASSERT_USER_ERROR(GImPlot->CurrentPlot != NULL, "TagY() needs to be called between BeginPlot() and EndPlot()!");
+ TagV(GImPlot->CurrentPlot->CurrentY, y, color, fmt, args);
+}
+
+static const float DRAG_GRAB_HALF_SIZE = 4.0f;
+
+bool DragPoint(int n_id, double* x, double* y, const ImVec4& col, float radius, ImPlotDragToolFlags flags) {
+ ImGui::PushID("#IMPLOT_DRAG_POINT");
+ IM_ASSERT_USER_ERROR(GImPlot->CurrentPlot != NULL, "DragPoint() needs to be called between BeginPlot() and EndPlot()!");
+ SetupLock();
+
+ if (!ImHasFlag(flags,ImPlotDragToolFlags_NoFit) && FitThisFrame()) {
+ FitPoint(ImPlotPoint(*x,*y));
+ }
+
+ const bool input = !ImHasFlag(flags, ImPlotDragToolFlags_NoInputs);
+ const bool show_curs = !ImHasFlag(flags, ImPlotDragToolFlags_NoCursors);
+ const bool no_delay = !ImHasFlag(flags, ImPlotDragToolFlags_Delayed);
+ const float grab_half_size = ImMax(DRAG_GRAB_HALF_SIZE, radius);
+ const ImVec4 color = IsColorAuto(col) ? ImGui::GetStyleColorVec4(ImGuiCol_Text) : col;
+ const ImU32 col32 = ImGui::ColorConvertFloat4ToU32(color);
+
+ ImVec2 pos = PlotToPixels(*x,*y,IMPLOT_AUTO,IMPLOT_AUTO);
+ const ImGuiID id = ImGui::GetCurrentWindow()->GetID(n_id);
+ ImRect rect(pos.x-grab_half_size,pos.y-grab_half_size,pos.x+grab_half_size,pos.y+grab_half_size);
+ bool hovered = false, held = false;
+
+ if (input)
+ ImGui::ButtonBehavior(rect,id,&hovered,&held);
+
+ bool dragging = false;
+ if (held && ImGui::IsMouseDragging(0)) {
+ *x = ImPlot::GetPlotMousePos(IMPLOT_AUTO,IMPLOT_AUTO).x;
+ *y = ImPlot::GetPlotMousePos(IMPLOT_AUTO,IMPLOT_AUTO).y;
+ dragging = true;
+ }
+
+ PushPlotClipRect();
+ ImDrawList& DrawList = *GetPlotDrawList();
+ if ((hovered || held) && show_curs)
+ ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
+ if (dragging && no_delay)
+ pos = PlotToPixels(*x,*y,IMPLOT_AUTO,IMPLOT_AUTO);
+ DrawList.AddCircleFilled(pos, radius, col32);
+ PopPlotClipRect();
+
+ ImGui::PopID();
+ return dragging;
+}
+
+bool DragLineX(int n_id, double* value, const ImVec4& col, float thickness, ImPlotDragToolFlags flags) {
+ ImGui::PushID("#IMPLOT_DRAG_LINE_X");
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "DragLineX() needs to be called between BeginPlot() and EndPlot()!");
- const float grab_size = ImMax(5.0f, thickness);
+ SetupLock();
+
+ if (!ImHasFlag(flags,ImPlotDragToolFlags_NoFit) && FitThisFrame()) {
+ FitPointX(*value);
+ }
+
+ const bool input = !ImHasFlag(flags, ImPlotDragToolFlags_NoInputs);
+ const bool show_curs = !ImHasFlag(flags, ImPlotDragToolFlags_NoCursors);
+ const bool no_delay = !ImHasFlag(flags, ImPlotDragToolFlags_Delayed);
+ const float grab_half_size = ImMax(DRAG_GRAB_HALF_SIZE, thickness/2);
float yt = gp.CurrentPlot->PlotRect.Min.y;
float yb = gp.CurrentPlot->PlotRect.Max.y;
- float x = IM_ROUND(PlotToPixels(*value,0).x);
- const bool outside = x < (gp.CurrentPlot->PlotRect.Min.x - grab_size / 2) || x > (gp.CurrentPlot->PlotRect.Max.x + grab_size / 2);
- if (outside)
- return false;
+ float x = IM_ROUND(PlotToPixels(*value,0,IMPLOT_AUTO,IMPLOT_AUTO).x);
+ const ImGuiID id = ImGui::GetCurrentWindow()->GetID(n_id);
+ ImRect rect(x-grab_half_size,yt,x+grab_half_size,yb);
+ bool hovered = false, held = false;
+
+ if (input)
+ ImGui::ButtonBehavior(rect,id,&hovered,&held);
+
+ if ((hovered || held) && show_curs)
+ ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeEW);
+
float len = gp.Style.MajorTickLen.x;
ImVec4 color = IsColorAuto(col) ? ImGui::GetStyleColorVec4(ImGuiCol_Text) : col;
ImU32 col32 = ImGui::ColorConvertFloat4ToU32(color);
- ImDrawList& DrawList = *GetPlotDrawList();
+
+ bool dragging = false;
+ if (held && ImGui::IsMouseDragging(0)) {
+ *value = ImPlot::GetPlotMousePos(IMPLOT_AUTO,IMPLOT_AUTO).x;
+ dragging = true;
+ }
+
PushPlotClipRect();
- DrawList.AddLine(ImVec2(x,yt), ImVec2(x,yb), col32, thickness);
+ ImDrawList& DrawList = *GetPlotDrawList();
+ if (dragging && no_delay)
+ x = IM_ROUND(PlotToPixels(*value,0,IMPLOT_AUTO,IMPLOT_AUTO).x);
+ DrawList.AddLine(ImVec2(x,yt), ImVec2(x,yb), col32, thickness);
DrawList.AddLine(ImVec2(x,yt), ImVec2(x,yt+len), col32, 3*thickness);
DrawList.AddLine(ImVec2(x,yb), ImVec2(x,yb-len), col32, 3*thickness);
PopPlotClipRect();
- if (gp.CurrentPlot->Selecting || gp.CurrentPlot->Querying)
- return false;
- ImVec2 old_cursor_pos = ImGui::GetCursorScreenPos();
- ImVec2 new_cursor_pos = ImVec2(x - grab_size / 2.0f, yt);
- ImGui::GetCurrentWindow()->DC.CursorPos = new_cursor_pos;
- ImGui::InvisibleButton(id, ImVec2(grab_size, yb-yt));
- ImGui::GetCurrentWindow()->DC.CursorPos = old_cursor_pos;
- if (ImGui::IsItemHovered() || ImGui::IsItemActive()) {
- gp.CurrentPlot->PlotHovered = false;
- ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeEW);
- if (show_label) {
- char buff[32];
- LabelAxisValue(gp.CurrentPlot->XAxis, gp.XTicks, *value, buff, 32);
- gp.Annotations.Append(ImVec2(x,yb),ImVec2(0,0),col32,CalcTextColor(color),true,"%s = %s", id, buff);
- }
- }
- bool dragging = false;
- if (ImGui::IsItemActive() && ImGui::IsMouseDragging(0)) {
- *value = ImPlot::GetPlotMousePos().x;
- *value = ImClamp(*value, gp.CurrentPlot->XAxis.Range.Min, gp.CurrentPlot->XAxis.Range.Max);
- dragging = true;
- }
+
+ ImGui::PopID();
return dragging;
}
-bool DragLineY(const char* id, double* value, bool show_label, const ImVec4& col, float thickness) {
+bool DragLineY(int n_id, double* value, const ImVec4& col, float thickness, ImPlotDragToolFlags flags) {
+ ImGui::PushID("#IMPLOT_DRAG_LINE_Y");
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "DragLineY() needs to be called between BeginPlot() and EndPlot()!");
- const float grab_size = ImMax(5.0f, thickness);
+ SetupLock();
+
+ if (!ImHasFlag(flags,ImPlotDragToolFlags_NoFit) && FitThisFrame()) {
+ FitPointY(*value);
+ }
+
+ const bool input = !ImHasFlag(flags, ImPlotDragToolFlags_NoInputs);
+ const bool show_curs = !ImHasFlag(flags, ImPlotDragToolFlags_NoCursors);
+ const bool no_delay = !ImHasFlag(flags, ImPlotDragToolFlags_Delayed);
+ const float grab_half_size = ImMax(DRAG_GRAB_HALF_SIZE, thickness/2);
float xl = gp.CurrentPlot->PlotRect.Min.x;
float xr = gp.CurrentPlot->PlotRect.Max.x;
- float y = IM_ROUND(PlotToPixels(0, *value).y);
- const bool outside = y < (gp.CurrentPlot->PlotRect.Min.y - grab_size / 2) || y > (gp.CurrentPlot->PlotRect.Max.y + grab_size / 2);
- if (outside)
- return false;
+ float y = IM_ROUND(PlotToPixels(0, *value,IMPLOT_AUTO,IMPLOT_AUTO).y);
+
+ const ImGuiID id = ImGui::GetCurrentWindow()->GetID(n_id);
+ ImRect rect(xl,y-grab_half_size,xr,y+grab_half_size);
+ bool hovered = false, held = false;
+
+ if (input)
+ ImGui::ButtonBehavior(rect,id,&hovered,&held);
+
+ if ((hovered || held) && show_curs)
+ ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeNS);
+
float len = gp.Style.MajorTickLen.y;
ImVec4 color = IsColorAuto(col) ? ImGui::GetStyleColorVec4(ImGuiCol_Text) : col;
ImU32 col32 = ImGui::ColorConvertFloat4ToU32(color);
- ImDrawList& DrawList = *GetPlotDrawList();
- PushPlotClipRect();
- DrawList.AddLine(ImVec2(xl,y), ImVec2(xr,y), col32, thickness);
- DrawList.AddLine(ImVec2(xl,y), ImVec2(xl+len,y), col32, 3*thickness);
- DrawList.AddLine(ImVec2(xr,y), ImVec2(xr-len,y), col32, 3*thickness);
- PopPlotClipRect();
- if (gp.CurrentPlot->Selecting || gp.CurrentPlot->Querying)
- return false;
- ImVec2 old_cursor_pos = ImGui::GetCursorScreenPos();
- ImVec2 new_cursor_pos = ImVec2(xl, y - grab_size / 2.0f);
- ImGui::SetItemAllowOverlap();
- ImGui::GetCurrentWindow()->DC.CursorPos = new_cursor_pos;
- ImGui::InvisibleButton(id, ImVec2(xr - xl, grab_size));
- ImGui::GetCurrentWindow()->DC.CursorPos = old_cursor_pos;
- int yax = GetCurrentYAxis();
- if (ImGui::IsItemHovered() || ImGui::IsItemActive()) {
- gp.CurrentPlot->PlotHovered = false;
- ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeNS);
- if (show_label) {
- char buff[32];
- LabelAxisValue(gp.CurrentPlot->YAxis[yax], gp.YTicks[yax], *value, buff, 32);
- gp.Annotations.Append(ImVec2(yax == 0 ? xl : xr,y), ImVec2(0,0), col32, CalcTextColor(color), true, "%s = %s", id, buff);
- }
- }
+
bool dragging = false;
- if (ImGui::IsItemActive() && ImGui::IsMouseDragging(0)) {
- *value = ImPlot::GetPlotMousePos().y;
- *value = ImClamp(*value, gp.CurrentPlot->YAxis[yax].Range.Min, gp.CurrentPlot->YAxis[yax].Range.Max);
+ if (held && ImGui::IsMouseDragging(0)) {
+ *value = ImPlot::GetPlotMousePos(IMPLOT_AUTO,IMPLOT_AUTO).y;
dragging = true;
}
- return dragging;
-}
-bool DragPoint(const char* id, double* x, double* y, bool show_label, const ImVec4& col, float radius) {
- ImPlotContext& gp = *GImPlot;
- IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "DragPoint() needs to be called between BeginPlot() and EndPlot()!");
- const float grab_size = ImMax(5.0f, 2*radius);
- const bool outside = !GetPlotLimits().Contains(*x,*y);
- if (outside)
- return false;
- const ImVec4 color = IsColorAuto(col) ? ImGui::GetStyleColorVec4(ImGuiCol_Text) : col;
- const ImU32 col32 = ImGui::ColorConvertFloat4ToU32(color);
- ImDrawList& DrawList = *GetPlotDrawList();
- const ImVec2 pos = PlotToPixels(*x,*y);
- int yax = GetCurrentYAxis();
- ImVec2 old_cursor_pos = ImGui::GetCursorScreenPos();
- ImVec2 new_cursor_pos = ImVec2(pos - ImVec2(grab_size,grab_size)*0.5f);
- ImGui::GetCurrentWindow()->DC.CursorPos = new_cursor_pos;
- ImGui::InvisibleButton(id, ImVec2(grab_size, grab_size));
- ImGui::GetCurrentWindow()->DC.CursorPos = old_cursor_pos;
PushPlotClipRect();
- if (ImGui::IsItemHovered() || ImGui::IsItemActive()) {
- DrawList.AddCircleFilled(pos, 1.5f*radius, (col32));
- gp.CurrentPlot->PlotHovered = false;
- if (show_label) {
- ImVec2 label_pos = pos + ImVec2(16 * GImGui->Style.MouseCursorScale, 8 * GImGui->Style.MouseCursorScale);
- char buff1[32];
- char buff2[32];
- LabelAxisValue(gp.CurrentPlot->XAxis, gp.XTicks, *x, buff1, 32);
- LabelAxisValue(gp.CurrentPlot->YAxis[yax], gp.YTicks[yax], *y, buff2, 32);
- gp.Annotations.Append(label_pos, ImVec2(0.0001f,0.00001f), col32, CalcTextColor(color), true, "%s = %s,%s", id, buff1, buff2);
- }
- }
- else {
- DrawList.AddCircleFilled(pos, radius, col32);
- }
+ ImDrawList& DrawList = *GetPlotDrawList();
+ if (dragging && no_delay)
+ y = IM_ROUND(PlotToPixels(0, *value,IMPLOT_AUTO,IMPLOT_AUTO).y);
+ DrawList.AddLine(ImVec2(xl,y), ImVec2(xr,y), col32, thickness);
+ DrawList.AddLine(ImVec2(xl,y), ImVec2(xl+len,y), col32, 3*thickness);
+ DrawList.AddLine(ImVec2(xr,y), ImVec2(xr-len,y), col32, 3*thickness);
PopPlotClipRect();
-
- bool dragging = false;
- if (ImGui::IsItemActive() && ImGui::IsMouseDragging(0)) {
- *x = ImPlot::GetPlotMousePos().x;
- *y = ImPlot::GetPlotMousePos().y;
- *x = ImClamp(*x, gp.CurrentPlot->XAxis.Range.Min, gp.CurrentPlot->XAxis.Range.Max);
- *y = ImClamp(*y, gp.CurrentPlot->YAxis[yax].Range.Min, gp.CurrentPlot->YAxis[yax].Range.Max);
- dragging = true;
- }
+ ImGui::PopID();
return dragging;
}
-//-----------------------------------------------------------------------------
-
-#define IMPLOT_ID_PLT 10030910
-#define IMPLOT_ID_LEG 10030911
-#define IMPLOT_ID_XAX 10030912
-#define IMPLOT_ID_YAX 10030913
-
-bool BeginDragDropTargetEx(int id, const ImRect& rect) {
- ImGuiContext& G = *GImGui;
- const ImGuiID ID = G.CurrentWindow->GetID(id);
- if (ImGui::ItemAdd(rect, ID, &rect) &&
- ImGui::BeginDragDropTarget())
- return true;
- return false;
-}
-
-bool BeginDragDropTarget() {
- return BeginDragDropTargetEx(IMPLOT_ID_PLT, GImPlot->CurrentPlot->PlotRect);
-}
-
-bool BeginDragDropTargetX() {
- return BeginDragDropTargetEx(IMPLOT_ID_XAX, GImPlot->CurrentPlot->XAxis.HoverRect);
-}
+bool DragRect(int n_id, double* x_min, double* y_min, double* x_max, double* y_max, const ImVec4& col, ImPlotDragToolFlags flags) {
+ ImGui::PushID("#IMPLOT_DRAG_RECT");
+ IM_ASSERT_USER_ERROR(GImPlot->CurrentPlot != NULL, "DragRect() needs to be called between BeginPlot() and EndPlot()!");
+ SetupLock();
-bool BeginDragDropTargetY(ImPlotYAxis axis) {
- return BeginDragDropTargetEx(IMPLOT_ID_YAX + axis, GImPlot->CurrentPlot->YAxis[axis].HoverRect);
-}
-
-bool BeginDragDropTargetLegend() {
- return !ImHasFlag(GImPlot->CurrentPlot->Flags,ImPlotFlags_NoLegend) &&
- BeginDragDropTargetEx(IMPLOT_ID_LEG, GImPlot->CurrentPlot->LegendRect);
-}
-
-void EndDragDropTarget() {
- ImGui::EndDragDropTarget();
-}
-
-bool BeginDragDropSourceEx(ImGuiID source_id, bool is_hovered, ImGuiDragDropFlags flags, ImGuiKeyModFlags key_mods) {
- ImGuiContext& g = *GImGui;
- ImGuiWindow* window = g.CurrentWindow;
- ImGuiMouseButton mouse_button = ImGuiMouseButton_Left;
-
- if (g.IO.MouseDown[mouse_button] == false) {
- if (g.ActiveId == source_id)
- ImGui::ClearActiveID();
- return false;
+ if (!ImHasFlag(flags,ImPlotDragToolFlags_NoFit) && FitThisFrame()) {
+ FitPoint(ImPlotPoint(*x_min,*y_min));
+ FitPoint(ImPlotPoint(*x_max,*y_max));
}
- if (is_hovered && g.IO.MouseClicked[mouse_button] && g.IO.KeyMods == key_mods) {
- ImGui::SetActiveID(source_id, window);
- ImGui::FocusWindow(window);
- }
+ const bool input = !ImHasFlag(flags, ImPlotDragToolFlags_NoInputs);
+ const bool show_curs = !ImHasFlag(flags, ImPlotDragToolFlags_NoCursors);
+ const bool no_delay = !ImHasFlag(flags, ImPlotDragToolFlags_Delayed);
+ bool h[] = {true,false,true,false};
+ double* x[] = {x_min,x_max,x_max,x_min};
+ double* y[] = {y_min,y_min,y_max,y_max};
+ ImVec2 p[4];
+ for (int i = 0; i < 4; ++i)
+ p[i] = PlotToPixels(*x[i],*y[i],IMPLOT_AUTO,IMPLOT_AUTO);
+ ImVec2 pc = PlotToPixels((*x_min+*x_max)/2,(*y_min+*y_max)/2,IMPLOT_AUTO,IMPLOT_AUTO);
+ ImRect rect(ImMin(p[0],p[2]),ImMax(p[0],p[2]));
+ ImRect rect_grab = rect; rect_grab.Expand(DRAG_GRAB_HALF_SIZE);
- if (g.ActiveId != source_id) {
- return false;
+ ImGuiMouseCursor cur[4];
+ if (show_curs) {
+ cur[0] = (rect.Min.x == p[0].x && rect.Min.y == p[0].y) || (rect.Max.x == p[0].x && rect.Max.y == p[0].y) ? ImGuiMouseCursor_ResizeNWSE : ImGuiMouseCursor_ResizeNESW;
+ cur[1] = cur[0] == ImGuiMouseCursor_ResizeNWSE ? ImGuiMouseCursor_ResizeNESW : ImGuiMouseCursor_ResizeNWSE;
+ cur[2] = cur[1] == ImGuiMouseCursor_ResizeNWSE ? ImGuiMouseCursor_ResizeNESW : ImGuiMouseCursor_ResizeNWSE;
+ cur[3] = cur[2] == ImGuiMouseCursor_ResizeNWSE ? ImGuiMouseCursor_ResizeNESW : ImGuiMouseCursor_ResizeNWSE;
}
- g.ActiveIdAllowOverlap = is_hovered;
- g.ActiveIdUsingNavDirMask = ~(ImU32)0;
- g.ActiveIdUsingNavInputMask = ~(ImU32)0;
- g.ActiveIdUsingKeyInputMask = ~(ImU64)0;
+ ImVec4 color = IsColorAuto(col) ? ImGui::GetStyleColorVec4(ImGuiCol_Text) : col;
+ ImU32 col32 = ImGui::ColorConvertFloat4ToU32(color);
+ color.w *= 0.25f;
+ ImU32 col32_a = ImGui::ColorConvertFloat4ToU32(color);
+ const ImGuiID id = ImGui::GetCurrentWindow()->GetID(n_id);
- if (ImGui::IsMouseDragging(mouse_button)) {
+ bool dragging = false;
+ bool hovered = false, held = false;
+ ImRect b_rect(pc.x-DRAG_GRAB_HALF_SIZE,pc.y-DRAG_GRAB_HALF_SIZE,pc.x+DRAG_GRAB_HALF_SIZE,pc.y+DRAG_GRAB_HALF_SIZE);
- if (!g.DragDropActive) {
- ImGui::ClearDragDrop();
- ImGuiPayload& payload = g.DragDropPayload;
- payload.SourceId = source_id;
- payload.SourceParentId = 0;
- g.DragDropActive = true;
- g.DragDropSourceFlags = 0;
- g.DragDropMouseButton = mouse_button;
- }
- g.DragDropSourceFrameCount = g.FrameCount;
- g.DragDropWithinSource = true;
+ if (input)
+ ImGui::ButtonBehavior(b_rect,id,&hovered,&held);
- if (!(flags & ImGuiDragDropFlags_SourceNoPreviewTooltip)) {
- ImGui::BeginTooltip();
- if (g.DragDropAcceptIdPrev && (g.DragDropAcceptFlags & ImGuiDragDropFlags_AcceptNoPreviewTooltip)) {
- ImGuiWindow* tooltip_window = g.CurrentWindow;
- tooltip_window->SkipItems = true;
- tooltip_window->HiddenFramesCanSkipItems = 1;
- }
+ if ((hovered || held) && show_curs)
+ ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeAll);
+ if (held && ImGui::IsMouseDragging(0)) {
+ for (int i = 0; i < 4; ++i) {
+ ImPlotPoint pp = PixelsToPlot(p[i] + ImGui::GetIO().MouseDelta,IMPLOT_AUTO,IMPLOT_AUTO);
+ *y[i] = pp.y;
+ *x[i] = pp.x;
}
- return true;
- }
- return false;
-}
-
-bool BeginDragDropSource(ImGuiKeyModFlags key_mods, ImGuiDragDropFlags flags) {
- if (ImGui::GetIO().KeyMods == key_mods) {
- GImPlot->CurrentPlot->XAxis.Dragging = false;
- for (int i = 0; i < IMPLOT_Y_AXES; ++i)
- GImPlot->CurrentPlot->YAxis[i].Dragging = false;
+ dragging = true;
}
- const ImGuiID ID = GImGui->CurrentWindow->GetID(IMPLOT_ID_PLT);
- ImRect rect = GImPlot->CurrentPlot->PlotRect;
- return ImGui::ItemAdd(rect, ID, &rect) && BeginDragDropSourceEx(ID, GImPlot->CurrentPlot->PlotHovered, flags, key_mods);
-}
-bool BeginDragDropSourceX(ImGuiKeyModFlags key_mods, ImGuiDragDropFlags flags) {
- if (ImGui::GetIO().KeyMods == key_mods)
- GImPlot->CurrentPlot->XAxis.Dragging = false;
- const ImGuiID ID = GImGui->CurrentWindow->GetID(IMPLOT_ID_XAX);
- ImRect rect = GImPlot->CurrentPlot->XAxis.HoverRect;
- return ImGui::ItemAdd(rect, ID, &rect) && BeginDragDropSourceEx(ID, GImPlot->CurrentPlot->XAxis.ExtHovered, flags, key_mods);
-}
-
-bool BeginDragDropSourceY(ImPlotYAxis axis, ImGuiKeyModFlags key_mods, ImGuiDragDropFlags flags) {
- if (ImGui::GetIO().KeyMods == key_mods)
- GImPlot->CurrentPlot->YAxis[axis].Dragging = false;
- const ImGuiID ID = GImGui->CurrentWindow->GetID(IMPLOT_ID_YAX + axis);
- ImRect rect = GImPlot->CurrentPlot->YAxis[axis].HoverRect;
- return ImGui::ItemAdd(rect, ID, &rect) && BeginDragDropSourceEx(ID, GImPlot->CurrentPlot->YAxis[axis].ExtHovered, flags, key_mods);
-}
+ for (int i = 0; i < 4; ++i) {
+ // points
+ b_rect = ImRect(p[i].x-DRAG_GRAB_HALF_SIZE,p[i].y-DRAG_GRAB_HALF_SIZE,p[i].x+DRAG_GRAB_HALF_SIZE,p[i].y+DRAG_GRAB_HALF_SIZE);
+ ImGuiID p_id = id + i + 1;
+ ImGui::KeepAliveID(p_id);
+ if (input)
+ ImGui::ButtonBehavior(b_rect,p_id,&hovered,&held);
+ if ((hovered || held) && show_curs)
+ ImGui::SetMouseCursor(cur[i]);
-bool BeginDragDropSourceItem(const char* label_id, ImGuiDragDropFlags flags) {
- ImPlotContext& gp = *GImPlot;
- IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "BeginDragDropSourceItem() needs to be called between BeginPlot() and EndPlot()!");
- ImGuiID source_id = ImGui::GetID(label_id);
- ImPlotItem* item = gp.CurrentPlot->Items.GetByKey(source_id);
- bool is_hovered = item && item->LegendHovered;
- return BeginDragDropSourceEx(source_id, is_hovered, flags, ImGuiKeyModFlags_None);
-}
+ if (held && ImGui::IsMouseDragging(0)) {
+ *x[i] = ImPlot::GetPlotMousePos(IMPLOT_AUTO,IMPLOT_AUTO).x;
+ *y[i] = ImPlot::GetPlotMousePos(IMPLOT_AUTO,IMPLOT_AUTO).y;
+ dragging = true;
+ }
-void EndDragDropSource() {
- ImGui::EndDragDropSource();
-}
+ // edges
+ ImVec2 e_min = ImMin(p[i],p[(i+1)%4]);
+ ImVec2 e_max = ImMax(p[i],p[(i+1)%4]);
+ b_rect = h[i] ? ImRect(e_min.x + DRAG_GRAB_HALF_SIZE, e_min.y - DRAG_GRAB_HALF_SIZE, e_max.x - DRAG_GRAB_HALF_SIZE, e_max.y + DRAG_GRAB_HALF_SIZE)
+ : ImRect(e_min.x - DRAG_GRAB_HALF_SIZE, e_min.y + DRAG_GRAB_HALF_SIZE, e_max.x + DRAG_GRAB_HALF_SIZE, e_max.y - DRAG_GRAB_HALF_SIZE);
+ ImGuiID e_id = id + i + 5;
+ ImGui::KeepAliveID(e_id);
+ if (input)
+ ImGui::ButtonBehavior(b_rect,e_id,&hovered,&held);
+ if ((hovered || held) && show_curs)
+ h[i] ? ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeNS) : ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeEW);
+ if (held && ImGui::IsMouseDragging(0)) {
+ if (h[i])
+ *y[i] = ImPlot::GetPlotMousePos(IMPLOT_AUTO,IMPLOT_AUTO).y;
+ else
+ *x[i] = ImPlot::GetPlotMousePos(IMPLOT_AUTO,IMPLOT_AUTO).x;
+ dragging = true;
+ }
+ if (hovered && ImGui::IsMouseDoubleClicked(0))
+ {
+ ImPlotRect b = GetPlotLimits(IMPLOT_AUTO,IMPLOT_AUTO);
+ if (h[i])
+ *y[i] = ((y[i] == y_min && *y_min < *y_max) || (y[i] == y_max && *y_max < *y_min)) ? b.Y.Min : b.Y.Max;
+ else
+ *x[i] = ((x[i] == x_min && *x_min < *x_max) || (x[i] == x_max && *x_max < *x_min)) ? b.X.Min : b.X.Max;
+ dragging = true;
+ }
+ }
-void ItemIcon(const ImVec4& col) {
- ItemIcon(ImGui::ColorConvertFloat4ToU32(col));
-}
-void ItemIcon(ImU32 col) {
- const float txt_size = ImGui::GetTextLineHeight();
- ImVec2 size(txt_size-4,txt_size);
- ImGuiWindow* window = ImGui::GetCurrentWindow();
- ImVec2 pos = window->DC.CursorPos;
- ImGui::GetWindowDrawList()->AddRectFilled(pos + ImVec2(0,2), pos + size - ImVec2(0,2), col);
- ImGui::Dummy(size);
+ PushPlotClipRect();
+ ImDrawList& DrawList = *GetPlotDrawList();
+ if (dragging && no_delay) {
+ for (int i = 0; i < 4; ++i)
+ p[i] = PlotToPixels(*x[i],*y[i],IMPLOT_AUTO,IMPLOT_AUTO);
+ pc = PlotToPixels((*x_min+*x_max)/2,(*y_min+*y_max)/2,IMPLOT_AUTO,IMPLOT_AUTO);
+ rect = ImRect(ImMin(p[0],p[2]),ImMax(p[0],p[2]));
+ }
+ DrawList.AddRectFilled(rect.Min, rect.Max, col32_a);
+ DrawList.AddRect(rect.Min, rect.Max, col32);
+ if (input && (dragging || rect_grab.Contains(ImGui::GetMousePos()))) {
+ DrawList.AddCircleFilled(pc,DRAG_GRAB_HALF_SIZE,col32);
+ for (int i = 0; i < 4; ++i)
+ DrawList.AddCircleFilled(p[i],DRAG_GRAB_HALF_SIZE,col32);
+ }
+ PopPlotClipRect();
+ ImGui::PopID();
+ return dragging;
}
-void ColormapIcon(ImPlotColormap cmap) {
- ImPlotContext& gp = *GImPlot;
- const float txt_size = ImGui::GetTextLineHeight();
- ImVec2 size(txt_size-4,txt_size);
- ImGuiWindow* window = ImGui::GetCurrentWindow();
- ImVec2 pos = window->DC.CursorPos;
- ImRect rect(pos+ImVec2(0,2),pos+size-ImVec2(0,2));
- ImDrawList& DrawList = *ImGui::GetWindowDrawList();
- RenderColorBar(gp.ColormapData.GetKeys(cmap),gp.ColormapData.GetKeyCount(cmap),DrawList,rect,false,false,!gp.ColormapData.IsQual(cmap));
- ImGui::Dummy(size);
+bool DragRect(int id, ImPlotRect* bounds, const ImVec4& col, ImPlotDragToolFlags flags) {
+ return DragRect(id, &bounds->X.Min, &bounds->Y.Min,&bounds->X.Max, &bounds->Y.Max, col, flags);
}
//-----------------------------------------------------------------------------
-
-void SetLegendLocation(ImPlotLocation location, ImPlotOrientation orientation, bool outside) {
- ImPlotContext& gp = *GImPlot;
- IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "SetLegendLocation() needs to be called between BeginPlot() and EndPlot()!");
- gp.CurrentPlot->LegendLocation = location;
- gp.CurrentPlot->LegendOrientation = orientation;
- if (gp.CurrentPlot->LegendOutside != outside)
- gp.CurrentPlot->LegendFlipSideNextFrame = true;
-}
-
-void SetMousePosLocation(ImPlotLocation location) {
- ImPlotContext& gp = *GImPlot;
- IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "SetMousePosLocation() needs to be called between BeginPlot() and EndPlot()!");
- gp.CurrentPlot->MousePosLocation = location;
-}
+// [SECTION] Legend Utils and Tools
+//-----------------------------------------------------------------------------
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);
- ImPlotItem* item = gp.CurrentPlot->Items.GetByKey(id);
+ IM_ASSERT_USER_ERROR(gp.CurrentItems != NULL, "IsPlotItemHighlight() needs to be called within an itemized context!");
+ SetupLock();
+ ImGuiID id = ImGui::GetIDWithSeed(label_id, NULL, gp.CurrentItems->ID);
+ ImPlotItem* item = gp.CurrentItems->GetItem(id);
return item && item->LegendHovered;
}
bool BeginLegendPopup(const char* label_id, ImGuiMouseButton mouse_button) {
ImPlotContext& gp = *GImPlot;
- IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "BeginLegendPopup() needs to be called between BeginPlot() and EndPlot()!");
+ IM_ASSERT_USER_ERROR(gp.CurrentItems != NULL, "BeginLegendPopup() needs to be called within an itemized context!");
+ SetupLock();
ImGuiWindow* window = GImGui->CurrentWindow;
if (window->SkipItems)
return false;
- ImGuiID id = ImGui::GetID(label_id);
+ ImGuiID id = ImGui::GetIDWithSeed(label_id, NULL, gp.CurrentItems->ID);
if (ImGui::IsMouseReleased(mouse_button)) {
- ImPlotItem* item = gp.CurrentPlot->Items.GetByKey(id);
+ ImPlotItem* item = gp.CurrentItems->GetItem(id);
if (item && item->LegendHovered)
ImGui::OpenPopupEx(id);
}
@@ -3162,10 +3971,11 @@ bool BeginLegendPopup(const char* label_id, ImGuiMouseButton mouse_button) {
}
void EndLegendPopup() {
+ SetupLock();
ImGui::EndPopup();
}
-void ShowAltLegend(const char* title_id, ImPlotOrientation orientation, const ImVec2 size, bool interactable) {
+void ShowAltLegend(const char* title_id, bool vertical, const ImVec2 size, bool interactable) {
ImPlotContext& gp = *GImPlot;
ImGuiContext &G = *GImGui;
ImGuiWindow * Window = G.CurrentWindow;
@@ -3176,7 +3986,7 @@ void ShowAltLegend(const char* title_id, ImPlotOrientation orientation, const Im
ImVec2 legend_size;
ImVec2 default_size = gp.Style.LegendPadding * 2;
if (plot != NULL) {
- legend_size = CalcLegendSize(*plot, gp.Style.LegendInnerPadding, gp.Style.LegendSpacing, orientation);
+ legend_size = CalcLegendSize(plot->Items, gp.Style.LegendInnerPadding, gp.Style.LegendSpacing, vertical);
default_size = legend_size + gp.Style.LegendPadding * 2;
}
ImVec2 frame_size = ImGui::CalcItemSize(size, default_size.x, default_size.y);
@@ -3196,16 +4006,116 @@ void ShowAltLegend(const char* title_id, ImPlotOrientation orientation, const Im
DrawList.AddRectFilled(legend_bb.Min, legend_bb.Max, col_bg);
DrawList.AddRect(legend_bb.Min, legend_bb.Max, col_bd);
// render entries
- ShowLegendEntries(*plot, legend_bb, interactable, gp.Style.LegendInnerPadding, gp.Style.LegendSpacing, orientation, DrawList);
+ ShowLegendEntries(plot->Items, legend_bb, interactable, gp.Style.LegendInnerPadding, gp.Style.LegendSpacing, vertical, DrawList);
}
DrawList.PopClipRect();
}
//-----------------------------------------------------------------------------
-// STYLING
+// [SECTION] Drag and Drop Utils
+//-----------------------------------------------------------------------------
+
+bool BeginDragDropTargetPlot() {
+ SetupLock();
+ ImRect rect = GImPlot->CurrentPlot->PlotRect;
+ return ImGui::BeginDragDropTargetCustom(rect, GImPlot->CurrentPlot->ID);
+}
+
+bool BeginDragDropTargetAxis(ImAxis axis) {
+ SetupLock();
+ ImPlotPlot& plot = *GImPlot->CurrentPlot;
+ ImPlotAxis& ax = plot.Axes[axis];
+ ImRect rect = ax.HoverRect;
+ rect.Expand(-3.5f);
+ return ImGui::BeginDragDropTargetCustom(rect, ax.ID);
+}
+
+bool BeginDragDropTargetLegend() {
+ SetupLock();
+ ImPlotItemGroup& items = *GImPlot->CurrentItems;
+ ImRect rect = items.Legend.Rect;
+ return ImGui::BeginDragDropTargetCustom(rect, items.ID);
+}
+
+void EndDragDropTarget() {
+ SetupLock();
+ ImGui::EndDragDropTarget();
+}
+
+bool BeginDragDropSourcePlot(ImGuiDragDropFlags flags) {
+ SetupLock();
+ ImPlotPlot* plot = GImPlot->CurrentPlot;
+ if (GImGui->IO.KeyMods == GImPlot->InputMap.OverrideMod || GImGui->DragDropPayload.SourceId == plot->ID)
+ return ImGui::ItemAdd(plot->PlotRect, plot->ID) && ImGui::BeginDragDropSource(flags);
+ return false;
+}
+
+bool BeginDragDropSourceAxis(ImAxis idx, ImGuiDragDropFlags flags) {
+ SetupLock();
+ ImPlotAxis& axis = GImPlot->CurrentPlot->Axes[idx];
+ if (GImGui->IO.KeyMods == GImPlot->InputMap.OverrideMod || GImGui->DragDropPayload.SourceId == axis.ID)
+ return ImGui::ItemAdd(axis.HoverRect, axis.ID) && ImGui::BeginDragDropSource(flags);
+ return false;
+}
+
+bool BeginDragDropSourceItem(const char* label_id, ImGuiDragDropFlags flags) {
+ SetupLock();
+ ImPlotContext& gp = *GImPlot;
+ IM_ASSERT_USER_ERROR(gp.CurrentItems != NULL, "BeginDragDropSourceItem() needs to be called within an itemized context!");
+ ImGuiID item_id = ImGui::GetIDWithSeed(label_id, NULL, gp.CurrentItems->ID);
+ ImPlotItem* item = gp.CurrentItems->GetItem(item_id);
+ if (item != NULL) {
+ return ImGui::ItemAdd(item->LegendHoverRect, item->ID) && ImGui::BeginDragDropSource(flags);
+ }
+ return false;
+}
+
+void EndDragDropSource() {
+ SetupLock();
+ ImGui::EndDragDropSource();
+}
+
+//-----------------------------------------------------------------------------
+// [SECTION] Aligned Plots
+//-----------------------------------------------------------------------------
+
+bool BeginAlignedPlots(const char* group_id, bool vertical) {
+ IM_ASSERT_USER_ERROR(GImPlot != NULL, "No current context. Did you call ImPlot::CreateContext() or ImPlot::SetCurrentContext()?");
+ IM_ASSERT_USER_ERROR(GImPlot->CurrentAlignmentH == NULL && GImPlot->CurrentAlignmentV == NULL, "Mismatched BeginAlignedPlots()/EndAlignedPlots()!");
+ ImPlotContext& gp = *GImPlot;
+ ImGuiContext &G = *GImGui;
+ ImGuiWindow * Window = G.CurrentWindow;
+ if (Window->SkipItems)
+ return false;
+ const ImGuiID ID = Window->GetID(group_id);
+ ImPlotAlignmentData* alignment = gp.AlignmentData.GetOrAddByKey(ID);
+ if (vertical)
+ gp.CurrentAlignmentV = alignment;
+ else
+ gp.CurrentAlignmentH = alignment;
+ if (alignment->Vertical != vertical)
+ alignment->Reset();
+ alignment->Vertical = vertical;
+ alignment->Begin();
+ return true;
+}
+
+void EndAlignedPlots() {
+ IM_ASSERT_USER_ERROR(GImPlot != NULL, "No current context. Did you call ImPlot::CreateContext() or ImPlot::SetCurrentContext()?");
+ IM_ASSERT_USER_ERROR(GImPlot->CurrentAlignmentH != NULL || GImPlot->CurrentAlignmentV != NULL, "Mismatched BeginAlignedPlots()/EndAlignedPlots()!");
+ ImPlotContext& gp = *GImPlot;
+ ImPlotAlignmentData* alignment = gp.CurrentAlignmentH != NULL ? gp.CurrentAlignmentH : (gp.CurrentAlignmentV != NULL ? gp.CurrentAlignmentV : NULL);
+ if (alignment)
+ alignment->End();
+ ResetCtxForNextAlignedPlots(GImPlot);
+}
+
+//-----------------------------------------------------------------------------
+// [SECTION] Plot and Item Styling
//-----------------------------------------------------------------------------
ImPlotStyle& GetStyle() {
+ IM_ASSERT_USER_ERROR(GImPlot != NULL, "No current context. Did you call ImPlot::CreateContext() or ImPlot::SetCurrentContext()?");
ImPlotContext& gp = *GImPlot;
return gp.Style;
}
@@ -3307,7 +4217,7 @@ void PopStyleVar(int count) {
}
//------------------------------------------------------------------------------
-// COLORMAPS
+// [Section] Colormaps
//------------------------------------------------------------------------------
ImPlotColormap AddColormap(const char* name, const ImVec4* colormap, int size, bool qual) {
@@ -3370,10 +4280,10 @@ void PopColormap(int count) {
ImU32 NextColormapColorU32() {
ImPlotContext& gp = *GImPlot;
- IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "NextColormapColor() needs to be called between BeginPlot() and EndPlot()!");
- int idx = gp.CurrentPlot->ColormapIdx % gp.ColormapData.GetKeyCount(gp.Style.Colormap);
+ IM_ASSERT_USER_ERROR(gp.CurrentItems != NULL, "NextColormapColor() needs to be called between BeginPlot() and EndPlot()!");
+ int idx = gp.CurrentItems->ColormapIdx % gp.ColormapData.GetKeyCount(gp.Style.Colormap);
ImU32 col = gp.ColormapData.GetKeyColor(gp.Style.Colormap, idx);
- gp.CurrentPlot->ColormapIdx++;
+ gp.CurrentItems->ColormapIdx++;
return col;
}
@@ -3385,7 +4295,7 @@ int GetColormapSize(ImPlotColormap cmap) {
ImPlotContext& gp = *GImPlot;
cmap = cmap == IMPLOT_AUTO ? gp.Style.Colormap : cmap;
IM_ASSERT_USER_ERROR(cmap >= 0 && cmap < gp.ColormapData.Count, "Invalid colormap index!");
- return gp.ColormapData.GetKeyCount(gp.Style.Colormap);
+ return gp.ColormapData.GetKeyCount(cmap);
}
ImU32 GetColormapColorU32(int idx, ImPlotColormap cmap) {
@@ -3468,10 +4378,10 @@ void ColormapScale(const char* label, double scale_min, double scale_max, const
ImPlotRange range(scale_min,scale_max);
gp.CTicks.Reset();
- AddTicksDefault(range, frame_size.y, ImPlotOrientation_Vertical, gp.CTicks, fmt);
+ AddTicksDefault(range, frame_size.y, true, gp.CTicks, DefaultFormatter, (void*)fmt);
const float txt_off = gp.Style.LabelPadding.x;
- const float pad_right = txt_off + gp.CTicks.MaxWidth + (label_size.x > 0 ? txt_off + label_size.y : 0);
+ const float pad_right = txt_off + gp.CTicks.MaxSize.x + (label_size.x > 0 ? txt_off + label_size.y : 0);
float bar_w = 20;
if (frame_size.x == 0)
@@ -3493,7 +4403,7 @@ void ColormapScale(const char* label, double scale_min, double scale_max, const
ImGui::PushClipRect(bb_frame.Min, bb_frame.Max, true);
RenderColorBar(gp.ColormapData.GetKeys(cmap), gp.ColormapData.GetKeyCount(cmap), DrawList, bb_grad, true, true, !gp.ColormapData.IsQual(cmap));
- const ImU32 col_tick = GetStyleColorU32(ImPlotCol_YAxis);
+ const ImU32 col_tick = GetStyleColorU32(ImPlotCol_AxisText);
const ImU32 col_text = ImGui::GetColorU32(ImGuiCol_Text);
for (int i = 0; i < gp.CTicks.Size; ++i) {
const float ypos = ImRemap((float)gp.CTicks.Ticks[i].PlotPos, (float)range.Max, (float)range.Min, bb_grad.Min.y, bb_grad.Max.y);
@@ -3504,7 +4414,7 @@ void ColormapScale(const char* label, double scale_min, double scale_max, const
DrawList.AddText(ImVec2(bb_grad.Max.x-1, ypos) + ImVec2(txt_off, -gp.CTicks.Ticks[i].LabelSize.y * 0.5f), col_text, gp.CTicks.GetText(i));
}
if (label_size.x > 0) {
- ImVec2 label_pos(bb_grad.Max.x - 1 + 2*txt_off + gp.CTicks.MaxWidth, bb_grad.GetCenter().y + label_size.x*0.5f );
+ ImVec2 label_pos(bb_grad.Max.x - 1 + 2*txt_off + gp.CTicks.MaxSize.x, bb_grad.GetCenter().y + label_size.x*0.5f );
const char* label_end = ImGui::FindRenderedTextEnd(label);
AddTextVertical(&DrawList,label_pos,col_text,label,label_end);
}
@@ -3575,11 +4485,95 @@ bool ColormapButton(const char* label, const ImVec2& size_arg, ImPlotColormap cm
return pressed;
}
+//-----------------------------------------------------------------------------
+// [Section] Miscellaneous
+//-----------------------------------------------------------------------------
+
+ImPlotInputMap& GetInputMap() {
+ IM_ASSERT_USER_ERROR(GImPlot != NULL, "No current context. Did you call ImPlot::CreateContext() or ImPlot::SetCurrentContext()?");
+ ImPlotContext& gp = *GImPlot;
+ return gp.InputMap;
+}
+
+void MapInputDefault(ImPlotInputMap* dst) {
+ ImPlotInputMap& map = dst ? *dst : GetInputMap();
+ map.Pan = ImGuiMouseButton_Left;
+ map.PanMod = ImGuiKeyModFlags_None;
+ map.Fit = ImGuiMouseButton_Left;
+ map.Menu = ImGuiMouseButton_Right;
+ map.Select = ImGuiMouseButton_Right;
+ map.SelectMod = ImGuiKeyModFlags_None;
+ map.SelectCancel = ImGuiMouseButton_Left;
+ map.SelectHorzMod = ImGuiKeyModFlags_Alt;
+ map.SelectVertMod = ImGuiKeyModFlags_Shift;
+ map.OverrideMod = ImGuiKeyModFlags_Ctrl;
+ map.ZoomMod = ImGuiKeyModFlags_None;
+ map.ZoomRate = 0.1f;
+}
+
+void MapInputReverse(ImPlotInputMap* dst) {
+ ImPlotInputMap& map = dst ? *dst : GetInputMap();
+ map.Pan = ImGuiMouseButton_Right;
+ map.PanMod = ImGuiKeyModFlags_None;
+ map.Fit = ImGuiMouseButton_Left;
+ map.Menu = ImGuiMouseButton_Right;
+ map.Select = ImGuiMouseButton_Left;
+ map.SelectMod = ImGuiKeyModFlags_None;
+ map.SelectCancel = ImGuiMouseButton_Right;
+ map.SelectHorzMod = ImGuiKeyModFlags_Alt;
+ map.SelectVertMod = ImGuiKeyModFlags_Shift;
+ map.OverrideMod = ImGuiKeyModFlags_Ctrl;
+ map.ZoomMod = ImGuiKeyModFlags_None;
+ map.ZoomRate = 0.1f;
+}
//-----------------------------------------------------------------------------
-// Style Editor etc.
+// [Section] Miscellaneous
//-----------------------------------------------------------------------------
+void ItemIcon(const ImVec4& col) {
+ ItemIcon(ImGui::ColorConvertFloat4ToU32(col));
+}
+
+void ItemIcon(ImU32 col) {
+ const float txt_size = ImGui::GetTextLineHeight();
+ ImVec2 size(txt_size-4,txt_size);
+ ImGuiWindow* window = ImGui::GetCurrentWindow();
+ ImVec2 pos = window->DC.CursorPos;
+ ImGui::GetWindowDrawList()->AddRectFilled(pos + ImVec2(0,2), pos + size - ImVec2(0,2), col);
+ ImGui::Dummy(size);
+}
+
+void ColormapIcon(ImPlotColormap cmap) {
+ ImPlotContext& gp = *GImPlot;
+ const float txt_size = ImGui::GetTextLineHeight();
+ ImVec2 size(txt_size-4,txt_size);
+ ImGuiWindow* window = ImGui::GetCurrentWindow();
+ ImVec2 pos = window->DC.CursorPos;
+ ImRect rect(pos+ImVec2(0,2),pos+size-ImVec2(0,2));
+ ImDrawList& DrawList = *ImGui::GetWindowDrawList();
+ RenderColorBar(gp.ColormapData.GetKeys(cmap),gp.ColormapData.GetKeyCount(cmap),DrawList,rect,false,false,!gp.ColormapData.IsQual(cmap));
+ ImGui::Dummy(size);
+}
+
+ImDrawList* GetPlotDrawList() {
+ return ImGui::GetWindowDrawList();
+}
+
+void PushPlotClipRect(float expand) {
+ ImPlotContext& gp = *GImPlot;
+ IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "PushPlotClipRect() needs to be called between BeginPlot() and EndPlot()!");
+ SetupLock();
+ ImRect rect = gp.CurrentPlot->PlotRect;
+ rect.Expand(expand);
+ ImGui::PushClipRect(rect.Min, rect.Max, true);
+}
+
+void PopPlotClipRect() {
+ SetupLock();
+ ImGui::PopClipRect();
+}
+
static void HelpMarker(const char* desc) {
ImGui::TextDisabled("(?)");
if (ImGui::IsItemHovered()) {
@@ -3625,6 +4619,21 @@ bool ShowColormapSelector(const char* label) {
return set;
}
+bool ShowInputMapSelector(const char* label) {
+ static int map_idx = -1;
+ if (ImGui::Combo(label, &map_idx, "Default\0Reversed\0"))
+ {
+ switch (map_idx)
+ {
+ case 0: MapInputDefault(); break;
+ case 1: MapInputReverse(); break;
+ }
+ return true;
+ }
+ return false;
+}
+
+
void ShowStyleEditor(ImPlotStyle* ref) {
ImPlotContext& gp = *GImPlot;
ImPlotStyle& style = GetStyle();
@@ -3899,21 +4908,35 @@ void ShowUserGuide() {
ImGui::BulletText("Click legend label icons to show/hide plot items.");
}
-void ShowAxisMetrics(ImPlotAxis* axis, bool show_axis_rects) {
- ImGui::Bullet(); ImGui::Text("Flags: %d", axis->Flags);
- ImGui::Bullet(); ImGui::Text("Range: [%f,%f]",axis->Range.Min, axis->Range.Max);
- ImGui::Bullet(); ImGui::Text("Pixels: %f", axis->Pixels);
- ImGui::Bullet(); ImGui::Text("Aspect: %f", axis->GetAspect());
- ImGui::Bullet(); ImGui::Text("Dragging: %s", axis->Dragging ? "true" : "false");
- ImGui::Bullet(); ImGui::Text("ExtHovered: %s", axis->ExtHovered ? "true" : "false");
- ImGui::Bullet(); ImGui::Text("AllHovered: %s", axis->AllHovered ? "true" : "false");
- ImGui::Bullet(); ImGui::Text("Present: %s", axis->Present ? "true" : "false");
- ImGui::Bullet(); ImGui::Text("HasRange: %s", axis->HasRange ? "true" : "false");
- ImGui::Bullet(); ImGui::Text("LinkedMin: %p", (void*)axis->LinkedMin);
- ImGui::Bullet(); ImGui::Text("LinkedMax: %p", (void*)axis->LinkedMax);
- if (show_axis_rects) {
- ImDrawList& fg = *ImGui::GetForegroundDrawList();
- fg.AddRect(axis->HoverRect.Min, axis->HoverRect.Max, IM_COL32(0,255,0,255));
+void ShowTicksMetrics(const ImPlotTickCollection& ticks) {
+ ImGui::BulletText("Size: %d", ticks.Size);
+ ImGui::BulletText("MaxSize: [%f,%f]", ticks.MaxSize.x, ticks.MaxSize.y);
+}
+
+void ShowAxisMetrics(const ImPlotPlot& plot, const ImPlotAxis& axis) {
+ ImGui::BulletText("Label: %s", axis.LabelOffset == -1 ? "[none]" : plot.GetAxisLabel(axis));
+ ImGui::BulletText("Flags: 0x%08X", axis.Flags);
+ ImGui::BulletText("Range: [%f,%f]",axis.Range.Min, axis.Range.Max);
+ ImGui::BulletText("Pixels: %f", axis.PixelSize());
+ ImGui::BulletText("Aspect: %f", axis.GetAspect());
+ ImGui::BulletText(axis.OrthoAxis == NULL ? "OrtherAxis: NULL" : "OrthoAxis: 0x%08X", axis.OrthoAxis->ID);
+ ImGui::BulletText("LinkedMin: %p", (void*)axis.LinkedMin);
+ ImGui::BulletText("LinkedMax: %p", (void*)axis.LinkedMax);
+ ImGui::BulletText("HasRange: %s", axis.HasRange ? "true" : "false");
+ ImGui::BulletText("Hovered: %s", axis.Hovered ? "true" : "false");
+ ImGui::BulletText("Held: %s", axis.Held ? "true" : "false");
+
+ if (ImGui::TreeNode("Transform")) {
+ ImGui::BulletText("PixelMin: %f", axis.PixelMin);
+ ImGui::BulletText("PixelMax: %f", axis.PixelMax);
+ ImGui::BulletText("LinM: %f", axis.LinM);
+ ImGui::BulletText("LogD: %f", axis.LogD);
+ ImGui::TreePop();
+ }
+
+ if (ImGui::TreeNode("Ticks")) {
+ ShowTicksMetrics(axis.Ticks);
+ ImGui::TreePop();
}
}
@@ -3921,6 +4944,11 @@ void ShowMetricsWindow(bool* p_popen) {
static bool show_plot_rects = false;
static bool show_axes_rects = false;
+ static bool show_axis_rects = false;
+ static bool show_canvas_rects = false;
+ static bool show_frame_rects = false;
+ static bool show_subplot_frame_rects = false;
+ static bool show_subplot_grid_rects = false;
ImDrawList& fg = *ImGui::GetForegroundDrawList();
@@ -3930,6 +4958,7 @@ void ShowMetricsWindow(bool* p_popen) {
ImGui::Begin("ImPlot Metrics", p_popen);
ImGui::Text("ImPlot " IMPLOT_VERSION);
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
+ ImGui::Text("Mouse Position: [%.0f,%.0f]", io.MousePos.x, io.MousePos.y);
ImGui::Separator();
if (ImGui::TreeNode("Tools")) {
if (ImGui::Button("Bust Plot Cache"))
@@ -3937,66 +4966,131 @@ void ShowMetricsWindow(bool* p_popen) {
ImGui::SameLine();
if (ImGui::Button("Bust Item Cache"))
BustItemCache();
- ImGui::Checkbox("Show Plot Rects", &show_plot_rects);
- ImGui::Checkbox("Show Axes Rects", &show_axes_rects);
+ ImGui::Checkbox("Show Frame Rects", &show_frame_rects);
+ ImGui::Checkbox("Show Canvas Rects",&show_canvas_rects);
+ ImGui::Checkbox("Show Plot Rects", &show_plot_rects);
+ ImGui::Checkbox("Show Axes Rects", &show_axes_rects);
+ ImGui::Checkbox("Show Axis Rects", &show_axis_rects);
+ ImGui::Checkbox("Show Subplot Frame Rects", &show_subplot_frame_rects);
+ ImGui::Checkbox("Show Subplot Grid Rects", &show_subplot_grid_rects);
ImGui::TreePop();
}
- const int n_plots = gp.Plots.GetSize();
+ const int n_plots = gp.Plots.GetBufSize();
+ const int n_subplots = gp.Subplots.GetBufSize();
+ // render rects
+ for (int p = 0; p < n_plots; ++p) {
+ ImPlotPlot* plot = gp.Plots.GetByIndex(p);
+ if (show_frame_rects)
+ fg.AddRect(plot->FrameRect.Min, plot->FrameRect.Max, IM_COL32(255,0,255,255));
+ if (show_canvas_rects)
+ fg.AddRect(plot->CanvasRect.Min, plot->CanvasRect.Max, IM_COL32(0,255,255,255));
+ if (show_plot_rects)
+ fg.AddRect(plot->PlotRect.Min, plot->PlotRect.Max, IM_COL32(255,255,0,255));
+ if (show_axes_rects)
+ fg.AddRect(plot->AxesRect.Min, plot->AxesRect.Max, IM_COL32(0,255,128,255));
+ if (show_axis_rects) {
+ for (int i = 0; i < ImAxis_COUNT; ++i) {
+ if (plot->Axes[i].Enabled)
+ fg.AddRect(plot->Axes[i].HoverRect.Min, plot->Axes[i].HoverRect.Max, IM_COL32(0,255,0,255));
+ }
+ }
+ }
+ for (int p = 0; p < n_subplots; ++p) {
+ ImPlotSubplot* subplot = gp.Subplots.GetByIndex(p);
+ if (show_subplot_frame_rects)
+ fg.AddRect(subplot->FrameRect.Min, subplot->FrameRect.Max, IM_COL32(255,0,0,255));
+ if (show_subplot_grid_rects)
+ fg.AddRect(subplot->GridRect.Min, subplot->GridRect.Max, IM_COL32(0,0,255,255));
+ }
if (ImGui::TreeNode("Plots","Plots (%d)", n_plots)) {
for (int p = 0; p < n_plots; ++p) {
// plot
- ImPlotPlot* plot = gp.Plots.GetByIndex(p);
+ ImPlotPlot& plot = *gp.Plots.GetByIndex(p);
ImGui::PushID(p);
- if (ImGui::TreeNode("Plot", "Plot [ID=%u]", plot->ID)) {
- int n_items = plot->Items.GetSize();
+ if (ImGui::TreeNode("Plot", "Plot [0x%08X]", plot.ID)) {
+ int n_items = plot.Items.GetItemCount();
if (ImGui::TreeNode("Items", "Items (%d)", n_items)) {
for (int i = 0; i < n_items; ++i) {
- ImPlotItem* item = plot->Items.GetByIndex(i);
+ ImPlotItem* item = plot.Items.GetItemByIndex(i);
ImGui::PushID(i);
- if (ImGui::TreeNode("Item", "Item [ID=%u]", item->ID)) {
+ if (ImGui::TreeNode("Item", "Item [0x%08X]", item->ID)) {
ImGui::Bullet(); ImGui::Checkbox("Show", &item->Show);
ImGui::Bullet();
ImVec4 temp = ImGui::ColorConvertU32ToFloat4(item->Color);
if (ImGui::ColorEdit4("Color",&temp.x, ImGuiColorEditFlags_NoInputs))
item->Color = ImGui::ColorConvertFloat4ToU32(temp);
- ImGui::Bullet(); ImGui::Text("NameOffset: %d",item->NameOffset);
- ImGui::Bullet(); ImGui::Text("Name: %s", item->NameOffset != -1 ? plot->LegendData.Labels.Buf.Data + item->NameOffset : "N/A");
- ImGui::Bullet(); ImGui::Text("Hovered: %s",item->LegendHovered ? "true" : "false");
+ ImGui::BulletText("NameOffset: %d",item->NameOffset);
+ ImGui::BulletText("Name: %s", item->NameOffset != -1 ? plot.Items.Legend.Labels.Buf.Data + item->NameOffset : "N/A");
+ ImGui::BulletText("Hovered: %s",item->LegendHovered ? "true" : "false");
ImGui::TreePop();
}
ImGui::PopID();
}
ImGui::TreePop();
}
- if (ImGui::TreeNode("X-Axis")) {
- ShowAxisMetrics(&plot->XAxis, show_axes_rects);
- ImGui::TreePop();
- }
- if (ImGui::TreeNode("Y-Axis")) {
- ShowAxisMetrics(&plot->YAxis[0], show_axes_rects);
- ImGui::TreePop();
+ char buff[16];
+ for (int i = 0; i < IMPLOT_NUM_X_AXES; ++i) {
+ ImFormatString(buff,16,"X-Axis %d", i+1);
+ if (plot.XAxis(i).Enabled && ImGui::TreeNode(buff, "X-Axis %d [0x%08X]", i+1, plot.XAxis(i).ID)) {
+ ShowAxisMetrics(plot, plot.XAxis(i));
+ ImGui::TreePop();
+ }
}
- if (ImHasFlag(plot->Flags, ImPlotFlags_YAxis2) && ImGui::TreeNode("Y-Axis 2")) {
- ShowAxisMetrics(&plot->YAxis[1], show_axes_rects);
- ImGui::TreePop();
+ for (int i = 0; i < IMPLOT_NUM_Y_AXES; ++i) {
+ ImFormatString(buff,16,"Y-Axis %d", i+1);
+ if (plot.YAxis(i).Enabled && ImGui::TreeNode(buff, "Y-Axis %d [0x%08X]", i+1, plot.YAxis(i).ID)) {
+ ShowAxisMetrics(plot, plot.YAxis(i));
+ ImGui::TreePop();
+ }
}
- if (ImHasFlag(plot->Flags, ImPlotFlags_YAxis3) && ImGui::TreeNode("Y-Axis 3")) {
- ShowAxisMetrics(&plot->YAxis[2], show_axes_rects);
+ ImGui::BulletText("Title: %s", plot.HasTitle() ? plot.GetTitle() : "none");
+ ImGui::BulletText("Flags: 0x%08X", plot.Flags);
+ ImGui::BulletText("Initialized: %s", plot.Initialized ? "true" : "false");
+ ImGui::BulletText("Selecting: %s", plot.Selecting ? "true" : "false");
+ ImGui::BulletText("Selected: %s", plot.Selected ? "true" : "false");
+ ImGui::BulletText("Hovered: %s", plot.Hovered ? "true" : "false");
+ ImGui::BulletText("Held: %s", plot.Held ? "true" : "false");
+ ImGui::BulletText("LegendHovered: %s", plot.Items.Legend.Hovered ? "true" : "false");
+ ImGui::BulletText("ContextLocked: %s", plot.ContextLocked ? "true" : "false");
+ ImGui::TreePop();
+ }
+ ImGui::PopID();
+ }
+ ImGui::TreePop();
+ }
+
+ if (ImGui::TreeNode("Subplots","Subplots (%d)", n_subplots)) {
+ for (int p = 0; p < n_subplots; ++p) {
+ // plot
+ ImPlotSubplot& plot = *gp.Subplots.GetByIndex(p);
+ ImGui::PushID(p);
+ if (ImGui::TreeNode("Subplot", "Subplot [0x%08X]", plot.ID)) {
+ int n_items = plot.Items.GetItemCount();
+ if (ImGui::TreeNode("Items", "Items (%d)", n_items)) {
+ for (int i = 0; i < n_items; ++i) {
+ ImPlotItem* item = plot.Items.GetItemByIndex(i);
+ ImGui::PushID(i);
+ if (ImGui::TreeNode("Item", "Item [0x%08X]", item->ID)) {
+ ImGui::Bullet(); ImGui::Checkbox("Show", &item->Show);
+ ImGui::Bullet();
+ ImVec4 temp = ImGui::ColorConvertU32ToFloat4(item->Color);
+ if (ImGui::ColorEdit4("Color",&temp.x, ImGuiColorEditFlags_NoInputs))
+ item->Color = ImGui::ColorConvertFloat4ToU32(temp);
+
+ ImGui::BulletText("NameOffset: %d",item->NameOffset);
+ ImGui::BulletText("Name: %s", item->NameOffset != -1 ? plot.Items.Legend.Labels.Buf.Data + item->NameOffset : "N/A");
+ ImGui::BulletText("Hovered: %s",item->LegendHovered ? "true" : "false");
+ ImGui::TreePop();
+ }
+ ImGui::PopID();
+ }
ImGui::TreePop();
}
- ImGui::Bullet(); ImGui::Text("Flags: %d", plot->Flags);
- ImGui::Bullet(); ImGui::Text("Initialized: %s", plot->Initialized ? "true" : "false");
- ImGui::Bullet(); ImGui::Text("Selecting: %s", plot->Selecting ? "true" : "false");
- ImGui::Bullet(); ImGui::Text("Selected: %s", plot->Selected ? "true" : "false");
- ImGui::Bullet(); ImGui::Text("Querying: %s", plot->Querying ? "true" : "false");
- ImGui::Bullet(); ImGui::Text("Queried: %s", plot->Queried ? "true" : "false");
- ImGui::Bullet(); ImGui::Text("FrameHovered: %s", plot->FrameHovered ? "true" : "false");
- ImGui::Bullet(); ImGui::Text("PlotHovered: %s", plot->PlotHovered ? "true" : "false");
- ImGui::Bullet(); ImGui::Text("LegendHovered: %s", plot->LegendHovered ? "true" : "false");
+ ImGui::BulletText("Flags: 0x%08X", plot.Flags);
+ ImGui::BulletText("FrameHovered: %s", plot.FrameHovered ? "true" : "false");
+ ImGui::BulletText("LegendHovered: %s", plot.Items.Legend.Hovered ? "true" : "false");
ImGui::TreePop();
- if (show_plot_rects)
- fg.AddRect(plot->PlotRect.Min, plot->PlotRect.Max, IM_COL32(255,255,0,255));
}
ImGui::PopID();
}
@@ -4101,7 +5195,7 @@ bool ShowDatePicker(const char* id, int* level, ImPlotTime* t, const ImPlotTime*
GetTime(t_first_mo,&Tm);
const int first_wd = Tm.tm_wday;
// month year
- snprintf(buff, 32, "%s %d", MONTH_NAMES[this_mon], this_year);
+ ImFormatString(buff, 32, "%s %d", MONTH_NAMES[this_mon], this_year);
if (ImGui::Button(buff))
*level = 1;
ImGui::SameLine(5*cell_size.x);
@@ -4127,10 +5221,12 @@ bool ShowDatePicker(const char* id, int* level, ImPlotTime* t, const ImPlotTime*
for (int i = 0; i < 6; ++i) {
for (int j = 0; j < 7; ++j) {
if (mo == 0 && day > days_last_mo) {
- mo = 1; day = 1;
+ mo = 1;
+ day = 1;
}
else if (mo == 1 && day > days_this_mo) {
- mo = 2; day = 1;
+ mo = 2;
+ day = 1;
}
const int now_yr = (mo == 0 && this_mon == 0) ? last_year : ((mo == 2 && this_mon == 11) ? next_year : this_year);
const int now_mo = mo == 0 ? last_mon : (mo == 1 ? this_mon : next_mon);
@@ -4147,7 +5243,7 @@ bool ShowDatePicker(const char* id, int* level, ImPlotTime* t, const ImPlotTime*
ImGui::PushStyleColor(ImGuiCol_Text, col_txt);
}
ImGui::PushID(i*7+j);
- snprintf(buff,32,"%d",day);
+ ImFormatString(buff,32,"%d",day);
if (now_yr == min_yr-1 || now_yr == max_yr+1) {
ImGui::Dummy(cell_size);
}
@@ -4171,7 +5267,7 @@ bool ShowDatePicker(const char* id, int* level, ImPlotTime* t, const ImPlotTime*
*t = FloorTime(*t, ImPlotTimeUnit_Mo);
GetTime(*t, &Tm);
int this_yr = Tm.tm_year + 1900;
- snprintf(buff, 32, "%d", this_yr);
+ ImFormatString(buff, 32, "%d", this_yr);
if (ImGui::Button(buff))
*level = 2;
BeginDisabledControls(this_yr <= min_yr);
@@ -4211,7 +5307,7 @@ bool ShowDatePicker(const char* id, int* level, ImPlotTime* t, const ImPlotTime*
int this_yr = GetYear(*t);
int yr = this_yr - this_yr % 20;
ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true);
- snprintf(buff,32,"%d-%d",yr,yr+19);
+ ImFormatString(buff,32,"%d-%d",yr,yr+19);
ImGui::Button(buff);
ImGui::PopItemFlag();
ImGui::SameLine(5*cell_size.x);
@@ -4232,7 +5328,7 @@ bool ShowDatePicker(const char* id, int* level, ImPlotTime* t, const ImPlotTime*
const bool t1_or_t2 = (t1 != NULL && t1_yr == yr) || (t2 != NULL && t2_yr == yr);
if (t1_or_t2)
ImGui::PushStyleColor(ImGuiCol_Button, col_btn);
- snprintf(buff,32,"%d",yr);
+ ImFormatString(buff,32,"%d",yr);
if (yr<1970||yr>3000) {
ImGui::Dummy(cell_size);
}
@@ -4329,7 +5425,7 @@ bool ShowTimePicker(const char* id, ImPlotTime* t) {
}
if (!hour24) {
ImGui::SameLine();
- if (ImGui::Button(am_pm[ap],ImVec2(height,height))) {
+ if (ImGui::Button(am_pm[ap],ImVec2(0,height))) {
ap = 1 - ap;
changed = true;
}
@@ -4371,16 +5467,13 @@ void StyleColorsAuto(ImPlotStyle* dst) {
colors[ImPlotCol_TitleText] = IMPLOT_AUTO_COL;
colors[ImPlotCol_InlayText] = IMPLOT_AUTO_COL;
colors[ImPlotCol_PlotBorder] = IMPLOT_AUTO_COL;
- colors[ImPlotCol_XAxis] = IMPLOT_AUTO_COL;
- colors[ImPlotCol_XAxisGrid] = IMPLOT_AUTO_COL;
- colors[ImPlotCol_YAxis] = IMPLOT_AUTO_COL;
- colors[ImPlotCol_YAxisGrid] = IMPLOT_AUTO_COL;
- colors[ImPlotCol_YAxis2] = IMPLOT_AUTO_COL;
- colors[ImPlotCol_YAxisGrid2] = IMPLOT_AUTO_COL;
- colors[ImPlotCol_YAxis3] = IMPLOT_AUTO_COL;
- colors[ImPlotCol_YAxisGrid3] = IMPLOT_AUTO_COL;
+ colors[ImPlotCol_AxisText] = IMPLOT_AUTO_COL;
+ colors[ImPlotCol_AxisGrid] = IMPLOT_AUTO_COL;
+ colors[ImPlotCol_AxisTick] = IMPLOT_AUTO_COL;
+ colors[ImPlotCol_AxisBg] = IMPLOT_AUTO_COL;
+ colors[ImPlotCol_AxisBgHovered] = IMPLOT_AUTO_COL;
+ colors[ImPlotCol_AxisBgActive] = IMPLOT_AUTO_COL;
colors[ImPlotCol_Selection] = IMPLOT_AUTO_COL;
- colors[ImPlotCol_Query] = IMPLOT_AUTO_COL;
colors[ImPlotCol_Crosshairs] = IMPLOT_AUTO_COL;
}
@@ -4403,16 +5496,13 @@ void StyleColorsClassic(ImPlotStyle* dst) {
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_AxisText] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f);
+ colors[ImPlotCol_AxisGrid] = ImVec4(0.90f, 0.90f, 0.90f, 0.25f);
+ colors[ImPlotCol_AxisTick] = IMPLOT_AUTO_COL; // TODO
+ colors[ImPlotCol_AxisBg] = IMPLOT_AUTO_COL; // TODO
+ colors[ImPlotCol_AxisBgHovered] = IMPLOT_AUTO_COL; // TODO
+ colors[ImPlotCol_AxisBgActive] = IMPLOT_AUTO_COL; // TODO
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);
}
@@ -4435,16 +5525,13 @@ void StyleColorsDark(ImPlotStyle* dst) {
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_AxisText] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
+ colors[ImPlotCol_AxisGrid] = ImVec4(1.00f, 1.00f, 1.00f, 0.25f);
+ colors[ImPlotCol_AxisTick] = IMPLOT_AUTO_COL; // TODO
+ colors[ImPlotCol_AxisBg] = IMPLOT_AUTO_COL; // TODO
+ colors[ImPlotCol_AxisBgHovered] = IMPLOT_AUTO_COL; // TODO
+ colors[ImPlotCol_AxisBgActive] = IMPLOT_AUTO_COL; // TODO
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);
}
@@ -4467,17 +5554,37 @@ void StyleColorsLight(ImPlotStyle* dst) {
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(0.00f, 0.00f, 0.00f, 0.50f);
- colors[ImPlotCol_YAxis3] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f);
- colors[ImPlotCol_YAxisGrid3] = ImVec4(0.00f, 0.00f, 0.00f, 0.50f);
+ colors[ImPlotCol_AxisText] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f);
+ colors[ImPlotCol_AxisGrid] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
+ colors[ImPlotCol_AxisTick] = ImVec4(0.00f, 0.00f, 0.00f, 0.25f);
+ colors[ImPlotCol_AxisBg] = IMPLOT_AUTO_COL; // TODO
+ colors[ImPlotCol_AxisBgHovered] = IMPLOT_AUTO_COL; // TODO
+ colors[ImPlotCol_AxisBgActive] = IMPLOT_AUTO_COL; // TODO
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);
}
+//-----------------------------------------------------------------------------
+// [SECTION] Obsolete Functions/Types
+//-----------------------------------------------------------------------------
+
+#ifndef IMPLOT_DISABLE_OBSOLETE_FUNCTIONS
+
+bool BeginPlot(const char* title, const char* x_label, const char* y1_label, const ImVec2& size,
+ ImPlotFlags flags, ImPlotAxisFlags x_flags, ImPlotAxisFlags y1_flags, ImPlotAxisFlags y2_flags, ImPlotAxisFlags y3_flags,
+ const char* y2_label, const char* y3_label)
+{
+ if (!BeginPlot(title, size, flags))
+ return false;
+ SetupAxis(ImAxis_X1, x_label, x_flags);
+ SetupAxis(ImAxis_Y1, y1_label, y1_flags);
+ if (ImHasFlag(flags, ImPlotFlags_YAxis2))
+ SetupAxis(ImAxis_Y2, y2_label, y2_flags);
+ if (ImHasFlag(flags, ImPlotFlags_YAxis3))
+ SetupAxis(ImAxis_Y3, y3_label, y3_flags);
+ return true;
+}
+
+#endif
+
} // namespace ImPlot
diff --git a/3rdparty/implot/implot.h b/3rdparty/implot/implot.h
index e486748..8226eda 100644
--- a/3rdparty/implot/implot.h
+++ b/3rdparty/implot/implot.h
@@ -20,13 +20,35 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
-// ImPlot v0.10 WIP
+// ImPlot v0.13 WIP
+
+// Table of Contents:
+//
+// [SECTION] Macros and Defines
+// [SECTION] Enums and Types
+// [SECTION] Callbacks
+// [SECTION] Contexts
+// [SECTION] Begin/End Plot
+// [SECTION] Begin/End Subplot
+// [SECTION] Setup
+// [SECTION] SetNext
+// [SECTION] Plot Items
+// [SECTION] Plot Tools
+// [SECTION] Plot Utils
+// [SECTION] Legend Utils
+// [SECTION] Drag and Drop
+// [SECTION] Styling
+// [SECTION] Colormaps
+// [SECTION] Input Mapping
+// [SECTION] Miscellaneous
+// [SECTION] Demo
+// [SECTION] Obsolete API
#pragma once
#include "imgui.h"
//-----------------------------------------------------------------------------
-// Macros and Defines
+// [SECTION] Macros and Defines
//-----------------------------------------------------------------------------
// Define attributes of all API symbols declarations (e.g. for DLL under Windows)
@@ -37,69 +59,150 @@
#define IMPLOT_API
#endif
-// ImPlot version string
-#define IMPLOT_VERSION "0.10 WIP"
+// ImPlot version string.
+#define IMPLOT_VERSION "0.13 WIP"
// Indicates variable should deduced automatically.
#define IMPLOT_AUTO -1
// Special color used to indicate that a color should be deduced automatically.
#define IMPLOT_AUTO_COL ImVec4(0,0,0,-1)
+// Macro for templated plotting functions; keeps header clean.
+#define IMPLOT_TMP template <typename T> IMPLOT_API
//-----------------------------------------------------------------------------
-// Forward Declarations and Basic Types
+// [SECTION] Enums and Types
//-----------------------------------------------------------------------------
// Forward declarations
-struct ImPlotContext; // ImPlot context (opaque struct, see implot_internal.h)
+struct ImPlotContext; // ImPlot context (opaque struct, see implot_internal.h)
// Enums/Flags
-typedef int ImPlotFlags; // -> enum ImPlotFlags_
-typedef int ImPlotAxisFlags; // -> enum ImPlotAxisFlags_
-typedef int ImPlotCol; // -> enum ImPlotCol_
-typedef int ImPlotStyleVar; // -> enum ImPlotStyleVar_
-typedef int ImPlotMarker; // -> enum ImPlotMarker_
-typedef int ImPlotColormap; // -> enum ImPlotColormap_
-typedef int ImPlotLocation; // -> enum ImPlotLocation_
-typedef int ImPlotOrientation; // -> enum ImPlotOrientation_
-typedef int ImPlotYAxis; // -> enum ImPlotYAxis_;
-typedef int ImPlotBin; // -> enum ImPlotBin_
+typedef int ImAxis; // -> enum ImAxis_
+typedef int ImPlotFlags; // -> enum ImPlotFlags_
+typedef int ImPlotAxisFlags; // -> enum ImPlotAxisFlags_
+typedef int ImPlotSubplotFlags; // -> enum ImPlotSubplotFlags_
+typedef int ImPlotLegendFlags; // -> enum ImPlotLegendFlags_
+typedef int ImPlotMouseTextFlags; // -> enum ImPlotMouseTextFlags_
+typedef int ImPlotDragToolFlags; // -> ImPlotDragToolFlags_
+typedef int ImPlotBarGroupsFlags; // -> ImPlotBarGroupsFlags_
+
+typedef int ImPlotCond; // -> enum ImPlotCond_
+typedef int ImPlotCol; // -> enum ImPlotCol_
+typedef int ImPlotStyleVar; // -> enum ImPlotStyleVar_
+typedef int ImPlotMarker; // -> enum ImPlotMarker_
+typedef int ImPlotColormap; // -> enum ImPlotColormap_
+typedef int ImPlotLocation; // -> enum ImPlotLocation_
+typedef int ImPlotBin; // -> enum ImPlotBin_
+
+// Axis indices. The values assigned may change; NEVER hardcode these.
+enum ImAxis_ {
+ // horizontal axes
+ ImAxis_X1 = 0, // enabled by default
+ ImAxis_X2, // disabled by default
+ ImAxis_X3, // disabled by default
+ // vertical axes
+ ImAxis_Y1, // enabled by default
+ ImAxis_Y2, // disabled by default
+ ImAxis_Y3, // disabled by default
+ // bookeeping
+ ImAxis_COUNT
+};
-// Options for plots.
+// Options for plots (see BeginPlot).
enum ImPlotFlags_ {
ImPlotFlags_None = 0, // default
ImPlotFlags_NoTitle = 1 << 0, // the plot title will not be displayed (titles are also hidden if preceeded by double hashes, e.g. "##MyPlot")
ImPlotFlags_NoLegend = 1 << 1, // the legend will not be displayed
- ImPlotFlags_NoMenus = 1 << 2, // the user will not be able to open context menus with right-click
- ImPlotFlags_NoBoxSelect = 1 << 3, // the user will not be able to box-select with right-click drag
- ImPlotFlags_NoMousePos = 1 << 4, // the mouse position, in plot coordinates, will not be displayed inside of the plot
- ImPlotFlags_NoHighlight = 1 << 5, // plot items will not be highlighted when their legend entry is hovered
+ ImPlotFlags_NoMouseText = 1 << 2, // the mouse position, in plot coordinates, will not be displayed inside of the plot
+ ImPlotFlags_NoInputs = 1 << 3, // the user will not be able to interact with the plot
+ ImPlotFlags_NoMenus = 1 << 4, // the user will not be able to open context menus
+ ImPlotFlags_NoBoxSelect = 1 << 5, // the user will not be able to box-select
ImPlotFlags_NoChild = 1 << 6, // a child window region will not be used to capture mouse scroll (can boost performance for single ImGui window applications)
- ImPlotFlags_Equal = 1 << 7, // primary x and y axes will be constrained to have the same units/pixel (does not apply to auxiliary y-axes)
- ImPlotFlags_YAxis2 = 1 << 8, // enable a 2nd y-axis on the right side
- ImPlotFlags_YAxis3 = 1 << 9, // enable a 3rd y-axis on the right side
- ImPlotFlags_Query = 1 << 10, // the user will be able to draw query rects with middle-mouse or CTRL + right-click drag
- ImPlotFlags_Crosshairs = 1 << 11, // the default mouse cursor will be replaced with a crosshair when hovered
- ImPlotFlags_AntiAliased = 1 << 12, // plot lines will be software anti-aliased (not recommended for high density plots, prefer MSAA)
- ImPlotFlags_CanvasOnly = ImPlotFlags_NoTitle | ImPlotFlags_NoLegend | ImPlotFlags_NoMenus | ImPlotFlags_NoBoxSelect | ImPlotFlags_NoMousePos
+ ImPlotFlags_NoFrame = 1 << 7, // the ImGui frame will not be rendered
+ ImPlotFlags_Equal = 1 << 8, // x and y axes pairs will be constrained to have the same units/pixel
+ ImPlotFlags_Crosshairs = 1 << 9, // the default mouse cursor will be replaced with a crosshair when hovered
+ ImPlotFlags_AntiAliased = 1 << 10, // plot items will be software anti-aliased (not recommended for high density plots, prefer MSAA)
+ ImPlotFlags_CanvasOnly = ImPlotFlags_NoTitle | ImPlotFlags_NoLegend | ImPlotFlags_NoMenus | ImPlotFlags_NoBoxSelect | ImPlotFlags_NoMouseText
};
-// Options for plot axes (X and Y).
+// Options for plot axes (see SetupAxis).
enum ImPlotAxisFlags_ {
ImPlotAxisFlags_None = 0, // default
ImPlotAxisFlags_NoLabel = 1 << 0, // the axis label will not be displayed (axis labels also hidden if the supplied string name is NULL)
ImPlotAxisFlags_NoGridLines = 1 << 1, // no grid lines will be displayed
ImPlotAxisFlags_NoTickMarks = 1 << 2, // no tick marks will be displayed
ImPlotAxisFlags_NoTickLabels = 1 << 3, // no text labels will be displayed
- ImPlotAxisFlags_Foreground = 1 << 4, // grid lines will be displayed in the foreground (i.e. on top of data) in stead of the background
- ImPlotAxisFlags_LogScale = 1 << 5, // a logartithmic (base 10) axis scale will be used (mutually exclusive with ImPlotAxisFlags_Time)
- ImPlotAxisFlags_Time = 1 << 6, // axis will display date/time formatted labels (mutually exclusive with ImPlotAxisFlags_LogScale)
- ImPlotAxisFlags_Invert = 1 << 7, // the axis will be inverted
- ImPlotAxisFlags_NoInitialFit = 1 << 8, // axis will not be initially fit to data extents on the first rendered frame (also the case if SetNextPlotLimits explicitly called)
- ImPlotAxisFlags_AutoFit = 1 << 9, // axis will be auto-fitting to data extents
- ImPlotAxisFlags_RangeFit = 1 << 10, // axis will only fit points if the point is in the visible range of the **orthoganol** axis
- ImPlotAxisFlags_LockMin = 1 << 11, // the axis minimum value will be locked when panning/zooming
- ImPlotAxisFlags_LockMax = 1 << 12, // the axis maximum value will be locked when panning/zooming
+ ImPlotAxisFlags_NoInitialFit = 1 << 4, // axis will not be initially fit to data extents on the first rendered frame
+ ImPlotAxisFlags_NoMenus = 1 << 5, // the user will not be able to open context menus with right-click
+ ImPlotAxisFlags_Opposite = 1 << 6, // axis ticks and labels will be rendered on conventionally opposite side (i.e, right or top)
+ ImPlotAxisFlags_Foreground = 1 << 7, // grid lines will be displayed in the foreground (i.e. on top of data) in stead of the background
+ ImPlotAxisFlags_LogScale = 1 << 8, // a logartithmic (base 10) axis scale will be used (mutually exclusive with ImPlotAxisFlags_Time)
+ ImPlotAxisFlags_Time = 1 << 9, // axis will display date/time formatted labels (mutually exclusive with ImPlotAxisFlags_LogScale)
+ ImPlotAxisFlags_Invert = 1 << 10, // the axis will be inverted
+ ImPlotAxisFlags_AutoFit = 1 << 11, // axis will be auto-fitting to data extents
+ ImPlotAxisFlags_RangeFit = 1 << 12, // axis will only fit points if the point is in the visible range of the **orthogonal** axis
+ ImPlotAxisFlags_LockMin = 1 << 13, // the axis minimum value will be locked when panning/zooming
+ ImPlotAxisFlags_LockMax = 1 << 14, // the axis maximum value will be locked when panning/zooming
ImPlotAxisFlags_Lock = ImPlotAxisFlags_LockMin | ImPlotAxisFlags_LockMax,
- ImPlotAxisFlags_NoDecorations = ImPlotAxisFlags_NoLabel | ImPlotAxisFlags_NoGridLines | ImPlotAxisFlags_NoTickMarks | ImPlotAxisFlags_NoTickLabels
+ ImPlotAxisFlags_NoDecorations = ImPlotAxisFlags_NoLabel | ImPlotAxisFlags_NoGridLines | ImPlotAxisFlags_NoTickMarks | ImPlotAxisFlags_NoTickLabels,
+ ImPlotAxisFlags_AuxDefault = ImPlotAxisFlags_NoGridLines | ImPlotAxisFlags_Opposite
+};
+
+// Options for subplots (see BeginSubplot).
+enum ImPlotSubplotFlags_ {
+ ImPlotSubplotFlags_None = 0, // default
+ ImPlotSubplotFlags_NoTitle = 1 << 0, // the subplot title will not be displayed (titles are also hidden if preceeded by double hashes, e.g. "##MySubplot")
+ ImPlotSubplotFlags_NoLegend = 1 << 1, // the legend will not be displayed (only applicable if ImPlotSubplotFlags_ShareItems is enabled)
+ ImPlotSubplotFlags_NoMenus = 1 << 2, // the user will not be able to open context menus with right-click
+ ImPlotSubplotFlags_NoResize = 1 << 3, // resize splitters between subplot cells will be not be provided
+ ImPlotSubplotFlags_NoAlign = 1 << 4, // subplot edges will not be aligned vertically or horizontally
+ ImPlotSubplotFlags_ShareItems = 1 << 5, // items across all subplots will be shared and rendered into a single legend entry
+ ImPlotSubplotFlags_LinkRows = 1 << 6, // link the y-axis limits of all plots in each row (does not apply to auxiliary axes)
+ ImPlotSubplotFlags_LinkCols = 1 << 7, // link the x-axis limits of all plots in each column (does not apply to auxiliary axes)
+ ImPlotSubplotFlags_LinkAllX = 1 << 8, // link the x-axis limits in every plot in the subplot (does not apply to auxiliary axes)
+ ImPlotSubplotFlags_LinkAllY = 1 << 9, // link the y-axis limits in every plot in the subplot (does not apply to auxiliary axes)
+ ImPlotSubplotFlags_ColMajor = 1 << 10 // subplots are added in column major order instead of the default row major order
+};
+
+// Options for legends (see SetupLegend)
+enum ImPlotLegendFlags_ {
+ ImPlotLegendFlags_None = 0, // default
+ ImPlotLegendFlags_NoButtons = 1 << 0, // legend icons will not function as hide/show buttons
+ ImPlotLegendFlags_NoHighlightItem = 1 << 1, // plot items will not be highlighted when their legend entry is hovered
+ ImPlotLegendFlags_NoHighlightAxis = 1 << 2, // axes will not be highlighted when legend entries are hovered (only relevant if x/y-axis count > 1)
+ ImPlotLegendFlags_NoMenus = 1 << 3, // the user will not be able to open context menus with right-click
+ ImPlotLegendFlags_Outside = 1 << 4, // legend will be rendered outside of the plot area
+ ImPlotLegendFlags_Horizontal = 1 << 5, // legend entries will be displayed horizontally
+};
+
+// Options for mouse hover text (see SetupMouseText)
+enum ImPlotMouseTextFlags_ {
+ ImPlotMouseTextFlags_None = 0, // default
+ ImPlotMouseTextFlags_NoAuxAxes = 1 << 0, // only show the mouse position for primary axes
+ ImPlotMouseTextFlags_NoFormat = 1 << 1, // axes label formatters won't be used to render text
+ ImPlotMouseTextFlags_ShowAlways = 1 << 2, // always display mouse position even if plot not hovered
+};
+
+// Options for DragPoint, DragLine, DragRect
+enum ImPlotDragToolFlags_ {
+ ImPlotDragToolFlags_None = 0, // default
+ ImPlotDragToolFlags_NoCursors = 1 << 0, // drag tools won't change cursor icons when hovered or held
+ ImPlotDragToolFlags_NoFit = 1 << 1, // the drag tool won't be considered for plot fits
+ ImPlotDragToolFlags_NoInputs = 1 << 2, // lock the tool from user inputs
+ ImPlotDragToolFlags_Delayed = 1 << 3, // tool rendering will be delayed one frame; useful when applying position-constraints
+};
+
+// Flags for ImPlot::PlotBarGroups
+enum ImPlotBarGroupsFlags_ {
+ ImPlotBarGroupsFlags_None = 0, // default
+ ImPlotBarGroupsFlags_Stacked = 1 << 0, // items in a group will be stacked on top of each other
+};
+
+// Represents a condition for SetupAxisLimits etc. (same as ImGuiCond, but we only support a subset of those enums)
+enum ImPlotCond_
+{
+ ImPlotCond_None = ImGuiCond_None, // No condition (always set the variable), same as _Always
+ ImPlotCond_Always = ImGuiCond_Always, // No condition (always set the variable)
+ ImPlotCond_Once = ImGuiCond_Once, // Set the variable once per runtime session (only the first call will succeed)
};
// Plot styling colors.
@@ -119,16 +222,13 @@ enum ImPlotCol_ {
ImPlotCol_LegendText, // legend text color (defaults to ImPlotCol_InlayText)
ImPlotCol_TitleText, // plot title text color (defaults to ImGuiCol_Text)
ImPlotCol_InlayText, // color of text appearing inside of plots (defaults to ImGuiCol_Text)
- ImPlotCol_XAxis, // x-axis label and tick lables color (defaults to ImGuiCol_Text)
- ImPlotCol_XAxisGrid, // x-axis grid color (defaults to 25% ImPlotCol_XAxis)
- ImPlotCol_YAxis, // y-axis label and tick labels color (defaults to ImGuiCol_Text)
- ImPlotCol_YAxisGrid, // y-axis grid color (defaults to 25% ImPlotCol_YAxis)
- ImPlotCol_YAxis2, // 2nd y-axis label and tick labels color (defaults to ImGuiCol_Text)
- ImPlotCol_YAxisGrid2, // 2nd y-axis grid/label color (defaults to 25% ImPlotCol_YAxis2)
- ImPlotCol_YAxis3, // 3rd y-axis label and tick labels color (defaults to ImGuiCol_Text)
- ImPlotCol_YAxisGrid3, // 3rd y-axis grid/label color (defaults to 25% ImPlotCol_YAxis3)
+ ImPlotCol_AxisText, // axis label and tick lables color (defaults to ImGuiCol_Text)
+ ImPlotCol_AxisGrid, // axis grid color (defaults to 25% ImPlotCol_AxisText)
+ ImPlotCol_AxisTick, // axis tick color (defaults to AxisGrid)
+ ImPlotCol_AxisBg, // background color of axis hover region (defaults to transparent)
+ ImPlotCol_AxisBgHovered, // axis hover color (defaults to ImGuiCol_ButtonHovered)
+ ImPlotCol_AxisBgActive, // axis active color (defaults to ImGuiCol_ButtonActive)
ImPlotCol_Selection, // box-selection color (defaults to yellow)
- ImPlotCol_Query, // box-query color (defaults to green)
ImPlotCol_Crosshairs, // crosshairs color (defaults to ImPlotCol_PlotBorder)
ImPlotCol_COUNT
};
@@ -216,19 +316,6 @@ enum ImPlotLocation_ {
ImPlotLocation_SouthEast = ImPlotLocation_South | ImPlotLocation_East // bottom-right
};
-// Used to orient items on a plot (e.g. legends, labels, etc.)
-enum ImPlotOrientation_ {
- ImPlotOrientation_Horizontal, // left/right
- ImPlotOrientation_Vertical // up/down
-};
-
-// Enums for different y-axes.
-enum ImPlotYAxis_ {
- ImPlotYAxis_1 = 0, // left (default)
- ImPlotYAxis_2 = 1, // first on right side
- ImPlotYAxis_3 = 2 // second on right side
-};
-
// Enums for different automatic histogram binning methods (k = bin count or w = bin width)
enum ImPlotBin_ {
ImPlotBin_Sqrt = -1, // k = sqrt(n)
@@ -240,8 +327,8 @@ enum ImPlotBin_ {
// Double precision version of ImVec2 used by ImPlot. Extensible by end users.
struct ImPlotPoint {
double x, y;
- ImPlotPoint() { x = y = 0.0; }
- ImPlotPoint(double _x, double _y) { x = _x; y = _y; }
+ ImPlotPoint() { x = y = 0.0; }
+ ImPlotPoint(double _x, double _y) { x = _x; y = _y; }
ImPlotPoint(const ImVec2& p) { x = p.x; y = p.y; }
double operator[] (size_t idx) const { return (&x)[idx]; }
double& operator[] (size_t idx) { return (&x)[idx]; }
@@ -251,24 +338,28 @@ struct ImPlotPoint {
#endif
};
-// A range defined by a min/max value. Used for plot axes ranges.
+// Range defined by a min/max value.
struct ImPlotRange {
double Min, Max;
- ImPlotRange() { Min = 0; Max = 0; }
- ImPlotRange(double _min, double _max) { Min = _min; Max = _max; }
- bool Contains(double value) const { return value >= Min && value <= Max; };
- double Size() const { return Max - Min; };
+ ImPlotRange() { Min = 0; Max = 0; }
+ ImPlotRange(double _min, double _max) { Min = _min; Max = _max; }
+ bool Contains(double value) const { return value >= Min && value <= Max; }
+ double Size() const { return Max - Min; }
+ double Clamp(double value) const { return (value < Min) ? Min : (value > Max) ? Max : value; }
};
-// Combination of two ranges for X and Y axes.
-struct ImPlotLimits {
+// Combination of two range limits for X and Y axes. Also an AABB defined by Min()/Max().
+struct ImPlotRect {
ImPlotRange X, Y;
- ImPlotLimits() { }
- ImPlotLimits(double x_min, double x_max, double y_min, double y_max) { X.Min = x_min; X.Max = x_max; Y.Min = y_min; Y.Max = y_max; }
- bool Contains(const ImPlotPoint& p) const { return Contains(p.x, p.y); }
- bool Contains(double x, double y) const { return X.Contains(x) && Y.Contains(y); }
- ImPlotPoint Min() const { return ImPlotPoint(X.Min, Y.Min); }
- ImPlotPoint Max() const { return ImPlotPoint(X.Max, Y.Max); }
+ ImPlotRect() { }
+ ImPlotRect(double x_min, double x_max, double y_min, double y_max) { X.Min = x_min; X.Max = x_max; Y.Min = y_min; Y.Max = y_max; }
+ bool Contains(const ImPlotPoint& p) const { return Contains(p.x, p.y); }
+ bool Contains(double x, double y) const { return X.Contains(x) && Y.Contains(y); }
+ ImPlotPoint Size() const { return ImPlotPoint(X.Size(), Y.Size()); }
+ ImPlotPoint Clamp(const ImPlotPoint& p) { return Clamp(p.x, p.y); }
+ ImPlotPoint Clamp(double x, double y) { return ImPlotPoint(X.Clamp(x),Y.Clamp(y)); }
+ ImPlotPoint Min() const { return ImPlotPoint(X.Min, Y.Min); }
+ ImPlotPoint Max() const { return ImPlotPoint(X.Max, Y.Max); }
};
// Plot style structure
@@ -301,7 +392,7 @@ struct ImPlotStyle {
ImVec2 AnnotationPadding; // = 2,2 text padding around annotation labels
ImVec2 FitPadding; // = 0,0 additional fit padding as a percentage of the fit extents (e.g. ImVec2(0.1f,0.1f) adds 10% to the fit extents of X and Y)
ImVec2 PlotDefaultSize; // = 400,300 default size used when ImVec2(0,0) is passed to BeginPlot
- ImVec2 PlotMinSize; // = 300,225 minimum size plot frame can be when shrunk
+ ImVec2 PlotMinSize; // = 200,150 minimum size plot frame can be when shrunk
// style colors
ImVec4 Colors[ImPlotCol_COUNT]; // Array of styling colors. Indexable with ImPlotCol_ enums.
// colormap
@@ -314,14 +405,37 @@ struct ImPlotStyle {
IMPLOT_API ImPlotStyle();
};
+// Input mapping structure. Default values listed. See also MapInputDefault, MapInputReverse.
+struct ImPlotInputMap {
+ ImGuiMouseButton Pan; // LMB enables panning when held,
+ ImGuiKeyModFlags PanMod; // none optional modifier that must be held for panning/fitting
+ ImGuiMouseButton Fit; // LMB initiates fit when double clicked
+ ImGuiMouseButton Select; // RMB begins box selection when pressed and confirms selection when released
+ ImGuiMouseButton SelectCancel; // LMB cancels active box selection when pressed; cannot be same as Select
+ ImGuiKeyModFlags SelectMod; // none optional modifier that must be held for box selection
+ ImGuiKeyModFlags SelectHorzMod; // Alt expands active box selection horizontally to plot edge when held
+ ImGuiKeyModFlags SelectVertMod; // Shift expands active box selection vertically to plot edge when held
+ ImGuiMouseButton Menu; // RMB opens context menus (if enabled) when clicked
+ ImGuiKeyModFlags OverrideMod; // Ctrl when held, all input is ignored; used to enable axis/plots as DND sources
+ ImGuiKeyModFlags ZoomMod; // none optional modifier that must be held for scroll wheel zooming
+ float ZoomRate; // 0.1f zoom rate for scroll (e.g. 0.1f = 10% plot range every scroll click); make negative to invert
+ IMPLOT_API ImPlotInputMap();
+};
+
//-----------------------------------------------------------------------------
-// ImPlot End-User API
+// [SECTION] Callbacks
//-----------------------------------------------------------------------------
+// Callback signature for axis tick label formatter.
+typedef void (*ImPlotFormatter)(double value, char* buff, int size, void* user_data);
+
+// Callback signature for data getter.
+typedef ImPlotPoint (*ImPlotGetter)(void* user_data, int idx);
+
namespace ImPlot {
//-----------------------------------------------------------------------------
-// ImPlot Context
+// [SECTION] Contexts
//-----------------------------------------------------------------------------
// Creates a new ImPlot context. Call this after ImGui::CreateContext.
@@ -340,14 +454,14 @@ IMPLOT_API void SetCurrentContext(ImPlotContext* ctx);
IMPLOT_API void SetImGuiContext(ImGuiContext* ctx);
//-----------------------------------------------------------------------------
-// Begin/End Plot
+// [SECTION] Begin/End Plot
//-----------------------------------------------------------------------------
// Starts a 2D plotting context. If this function returns true, EndPlot() MUST
// be called! You are encouraged to use the following convention:
//
// if (BeginPlot(...)) {
-// ImPlot::PlotLine(...);
+// PlotLine(...);
// ...
// EndPlot();
// }
@@ -357,34 +471,178 @@ IMPLOT_API void SetImGuiContext(ImGuiContext* ctx);
// - #title_id must be unique to the current ImGui ID scope. If you need to avoid ID
// collisions or don't want to display a title in the plot, use double hashes
// (e.g. "MyPlot##HiddenIdText" or "##NoTitle").
-// - If #x_label and/or #y_label are provided, axes labels will be displayed.
// - #size is the **frame** size of the plot widget, not the plot area. The default
-// size of plots (i.e. when ImVec2(0,0)) can be modified in your ImPlotStyle
-// (default is 400x300 px).
-// - Auxiliary y-axes must be enabled with ImPlotFlags_YAxis2/3 to be displayed.
-// - See ImPlotFlags and ImPlotAxisFlags for more available options.
-
-IMPLOT_API bool BeginPlot(const char* title_id,
- const char* x_label = NULL,
- const char* y_label = NULL,
- const ImVec2& size = ImVec2(-1,0),
- ImPlotFlags flags = ImPlotFlags_None,
- ImPlotAxisFlags x_flags = ImPlotAxisFlags_None,
- ImPlotAxisFlags y_flags = ImPlotAxisFlags_None,
- ImPlotAxisFlags y2_flags = ImPlotAxisFlags_NoGridLines,
- ImPlotAxisFlags y3_flags = ImPlotAxisFlags_NoGridLines,
- const char* y2_label = NULL,
- const char* y3_label = NULL);
+// size of plots (i.e. when ImVec2(0,0)) can be modified in your ImPlotStyle.
+IMPLOT_API bool BeginPlot(const char* title_id, const ImVec2& size = ImVec2(-1,0), ImPlotFlags flags = ImPlotFlags_None);
// Only call EndPlot() if BeginPlot() returns true! Typically called at the end
// of an if statement conditioned on BeginPlot(). See example above.
IMPLOT_API void EndPlot();
//-----------------------------------------------------------------------------
-// Plot Items
+// [SECTION] Begin/End Subplots
+//-----------------------------------------------------------------------------
+
+// Starts a subdivided plotting context. If the function returns true,
+// EndSubplots() MUST be called! Call BeginPlot/EndPlot AT MOST [rows*cols]
+// times in between the begining and end of the subplot context. Plots are
+// added in row major order.
+//
+// Example:
+//
+// if (BeginSubplots("My Subplot",2,3,ImVec2(800,400)) {
+// for (int i = 0; i < 6; ++i) {
+// if (BeginPlot(...)) {
+// ImPlot::PlotLine(...);
+// ...
+// EndPlot();
+// }
+// }
+// EndSubplots();
+// }
+//
+// Produces:
+//
+// [0] | [1] | [2]
+// ----|-----|----
+// [3] | [4] | [5]
+//
+// Important notes:
+//
+// - #title_id must be unique to the current ImGui ID scope. If you need to avoid ID
+// collisions or don't want to display a title in the plot, use double hashes
+// (e.g. "MySubplot##HiddenIdText" or "##NoTitle").
+// - #rows and #cols must be greater than 0.
+// - #size is the size of the entire grid of subplots, not the individual plots
+// - #row_ratios and #col_ratios must have AT LEAST #rows and #cols elements,
+// respectively. These are the sizes of the rows and columns expressed in ratios.
+// If the user adjusts the dimensions, the arrays are updated with new ratios.
+//
+// Important notes regarding BeginPlot from inside of BeginSubplots:
+//
+// - The #title_id parameter of _BeginPlot_ (see above) does NOT have to be
+// unique when called inside of a subplot context. Subplot IDs are hashed
+// for your convenience so you don't have call PushID or generate unique title
+// strings. Simply pass an empty string to BeginPlot unless you want to title
+// each subplot.
+// - The #size parameter of _BeginPlot_ (see above) is ignored when inside of a
+// subplot context. The actual size of the subplot will be based on the
+// #size value you pass to _BeginSubplots_ and #row/#col_ratios if provided.
+
+IMPLOT_API bool BeginSubplots(const char* title_id,
+ int rows,
+ int cols,
+ const ImVec2& size,
+ ImPlotSubplotFlags flags = ImPlotSubplotFlags_None,
+ float* row_ratios = NULL,
+ float* col_ratios = NULL);
+
+// Only call EndSubplots() if BeginSubplots() returns true! Typically called at the end
+// of an if statement conditioned on BeginSublots(). See example above.
+IMPLOT_API void EndSubplots();
+
+//-----------------------------------------------------------------------------
+// [SECTION] Setup
+//-----------------------------------------------------------------------------
+
+// The following API allows you to setup and customize various aspects of the
+// current plot. The functions should be called immediately after BeginPlot
+// and before any other API calls. Typical usage is as follows:
+
+// if (BeginPlot(...)) { 1) begin a new plot
+// SetupAxis(ImAxis_X1, "My X-Axis"); 2) make Setup calls
+// SetupAxis(ImAxis_Y1, "My Y-Axis");
+// SetupLegend(ImPlotLocation_North);
+// ...
+// SetupFinish(); 3) [optional] explicitly finish setup
+// PlotLine(...); 4) plot items
+// ...
+// EndPlot(); 5) end the plot
+// }
+//
+// Important notes:
+//
+// - Always call Setup code at the top of your BeginPlot conditional statement.
+// - Setup is locked once you start plotting or explicitly call SetupFinish.
+// Do NOT call Setup code after you begin plotting or after you make
+// any non-Setup API calls (e.g. utils like PlotToPixels also lock Setup)
+// - Calling SetupFinish is OPTIONAL, but probably good practice. If you do not
+// call it yourself, then the first subsequent plotting or utility function will
+// call it for you.
+
+// Enables an axis or sets the label and/or flags for an existing axis. Leave #label = NULL for no label.
+IMPLOT_API void SetupAxis(ImAxis axis, const char* label = NULL, ImPlotAxisFlags flags = ImPlotAxisFlags_None);
+// Sets an axis range limits. If ImPlotCond_Always is used, the axes limits will be locked.
+IMPLOT_API void SetupAxisLimits(ImAxis axis, double v_min, double v_max, ImPlotCond cond = ImPlotCond_Once);
+// Links an axis range limits to external values. Set to NULL for no linkage. The pointer data must remain valid until EndPlot.
+IMPLOT_API void SetupAxisLinks(ImAxis axis, double* link_min, double* link_max);
+// Sets the format of numeric axis labels via formater specifier (default="%g"). Formated values will be double (i.e. use %f).
+IMPLOT_API void SetupAxisFormat(ImAxis axis, const char* fmt);
+// Sets the format of numeric axis labels via formatter callback. Given #value, write a label into #buff. Optionally pass user data.
+IMPLOT_API void SetupAxisFormat(ImAxis axis, ImPlotFormatter formatter, void* data = NULL);
+// Sets an axis' ticks and optionally the labels. To keep the default ticks, set #keep_default=true.
+IMPLOT_API void SetupAxisTicks(ImAxis axis, const double* values, int n_ticks, const char* const labels[] = NULL, bool keep_default = false);
+// Sets an axis' ticks and optionally the labels for the next plot. To keep the default ticks, set #keep_default=true.
+IMPLOT_API void SetupAxisTicks(ImAxis axis, double v_min, double v_max, int n_ticks, const char* const labels[] = NULL, bool keep_default = false);
+
+// Sets the label and/or flags for primary X and Y axes (shorthand for two calls to SetupAxis).
+IMPLOT_API void SetupAxes(const char* x_label, const char* y_label, ImPlotAxisFlags x_flags = ImPlotAxisFlags_None, ImPlotAxisFlags y_flags = ImPlotAxisFlags_None);
+// Sets the primary X and Y axes range limits. If ImPlotCond_Always is used, the axes limits will be locked (shorthand for two calls to SetupAxisLimits).
+IMPLOT_API void SetupAxesLimits(double x_min, double x_max, double y_min, double y_max, ImPlotCond cond = ImPlotCond_Once);
+
+// Sets up the plot legend.
+IMPLOT_API void SetupLegend(ImPlotLocation location, ImPlotLegendFlags flags = ImPlotLegendFlags_None);
+// Set the location of the current plot's mouse position text (default = South|East).
+IMPLOT_API void SetupMouseText(ImPlotLocation location, ImPlotMouseTextFlags flags = ImPlotMouseTextFlags_None);
+
+// Explicitly finalize plot setup. Once you call this, you cannot make anymore Setup calls for the current plot!
+// Note that calling this function is OPTIONAL; it will be called by the first subsequent setup-locking API call.
+IMPLOT_API void SetupFinish();
+
+//-----------------------------------------------------------------------------
+// [SECTION] SetNext
+//-----------------------------------------------------------------------------
+
+// Though you should default to the `Setup` API above, there are some scenarios
+// where (re)configuring a plot or axis before `BeginPlot` is needed (e.g. if
+// using a preceding button or slider widget to change the plot limits). In
+// this case, you can use the `SetNext` API below. While this is not as feature
+// rich as the Setup API, most common needs are provided. These functions can be
+// called anwhere except for inside of `Begin/EndPlot`. For example:
+
+// if (ImGui::Button("Center Plot"))
+// ImPlot::SetNextPlotLimits(-1,1,-1,1);
+// if (ImPlot::BeginPlot(...)) {
+// ...
+// ImPlot::EndPlot();
+// }
+//
+// Important notes:
+//
+// - You must still enable non-default axes with SetupAxis for these functions
+// to work properly.
+
+// Sets an upcoming axis range limits. If ImPlotCond_Always is used, the axes limits will be locked.
+IMPLOT_API void SetNextAxisLimits(ImAxis axis, double v_min, double v_max, ImPlotCond cond = ImPlotCond_Once);
+// Links an upcoming axis range limits to external values. Set to NULL for no linkage. The pointer data must remain valid until EndPlot!
+IMPLOT_API void SetNextAxisLinks(ImAxis axis, double* link_min, double* link_max);
+// Set an upcoming axis to auto fit to its data.
+IMPLOT_API void SetNextAxisToFit(ImAxis axis);
+
+// Sets the upcoming primary X and Y axes range limits. If ImPlotCond_Always is used, the axes limits will be locked (shorthand for two calls to SetupAxisLimits).
+IMPLOT_API void SetNextAxesLimits(double x_min, double x_max, double y_min, double y_max, ImPlotCond cond = ImPlotCond_Once);
+// Sets all upcoming axes to auto fit to their data.
+IMPLOT_API void SetNextAxesToFit();
+
+//-----------------------------------------------------------------------------
+// [SECTION] Plot Items
//-----------------------------------------------------------------------------
-// The template functions below are explicitly instantiated in implot_items.cpp.
+// The main plotting API is provied below. Call these functions between
+// Begin/EndPlot and after any Setup API calls. Each plots data on the current
+// x and y axes, which can be changed with `SetAxis/Axes`.
+//
+// The templated functions are explicitly instantiated in implot_items.cpp.
// They are not intended to be used generically with custom types. You will get
// a linker error if you try! All functions support the following scalar types:
//
@@ -429,71 +687,77 @@ IMPLOT_API void EndPlot();
// if you try plotting extremely large 64-bit integral types. Proceed with caution!
// Plots a standard 2D line plot.
-template <typename T> IMPLOT_API void PlotLine(const char* label_id, const T* values, int count, double xscale=1, double x0=0, int offset=0, int stride=sizeof(T));
-template <typename T> IMPLOT_API void PlotLine(const char* label_id, const T* xs, const T* ys, int count, int offset=0, int stride=sizeof(T));
- IMPLOT_API void PlotLineG(const char* label_id, ImPlotPoint (*getter)(void* data, int idx), void* data, int count, int offset=0);
+IMPLOT_TMP void PlotLine(const char* label_id, const T* values, int count, double xscale=1, double x0=0, int offset=0, int stride=sizeof(T));
+IMPLOT_TMP void PlotLine(const char* label_id, const T* xs, const T* ys, int count, int offset=0, int stride=sizeof(T));
+IMPLOT_API void PlotLineG(const char* label_id, ImPlotGetter getter, void* data, int count);
// Plots a standard 2D scatter plot. Default marker is ImPlotMarker_Circle.
-template <typename T> IMPLOT_API void PlotScatter(const char* label_id, const T* values, int count, double xscale=1, double x0=0, int offset=0, int stride=sizeof(T));
-template <typename T> IMPLOT_API void PlotScatter(const char* label_id, const T* xs, const T* ys, int count, int offset=0, int stride=sizeof(T));
- IMPLOT_API void PlotScatterG(const char* label_id, ImPlotPoint (*getter)(void* data, int idx), void* data, int count, int offset=0);
+IMPLOT_TMP void PlotScatter(const char* label_id, const T* values, int count, double xscale=1, double x0=0, int offset=0, int stride=sizeof(T));
+IMPLOT_TMP void PlotScatter(const char* label_id, const T* xs, const T* ys, int count, int offset=0, int stride=sizeof(T));
+IMPLOT_API void PlotScatterG(const char* label_id, ImPlotGetter getter, void* data, int count);
// Plots a a stairstep graph. The y value is continued constantly from every x position, i.e. the interval [x[i], x[i+1]) has the value y[i].
-template <typename T> IMPLOT_API void PlotStairs(const char* label_id, const T* values, int count, double xscale=1, double x0=0, int offset=0, int stride=sizeof(T));
-template <typename T> IMPLOT_API void PlotStairs(const char* label_id, const T* xs, const T* ys, int count, int offset=0, int stride=sizeof(T));
- IMPLOT_API void PlotStairsG(const char* label_id, ImPlotPoint (*getter)(void* data, int idx), void* data, int count, int offset=0);
+IMPLOT_TMP void PlotStairs(const char* label_id, const T* values, int count, double xscale=1, double x0=0, int offset=0, int stride=sizeof(T));
+IMPLOT_TMP void PlotStairs(const char* label_id, const T* xs, const T* ys, int count, int offset=0, int stride=sizeof(T));
+IMPLOT_API void PlotStairsG(const char* label_id, ImPlotGetter getter, void* data, int count);
-// Plots a shaded (filled) region between two lines, or a line and a horizontal reference. Set y_ref to +/-INFINITY for infinite fill extents.
-template <typename T> IMPLOT_API void PlotShaded(const char* label_id, const T* values, int count, double y_ref=0, double xscale=1, double x0=0, int offset=0, int stride=sizeof(T));
-template <typename T> IMPLOT_API void PlotShaded(const char* label_id, const T* xs, const T* ys, int count, double y_ref=0, int offset=0, int stride=sizeof(T));
-template <typename T> IMPLOT_API void PlotShaded(const char* label_id, const T* xs, const T* ys1, const T* ys2, int count, int offset=0, int stride=sizeof(T));
- IMPLOT_API void PlotShadedG(const char* label_id, ImPlotPoint (*getter1)(void* data, int idx), void* data1, ImPlotPoint (*getter2)(void* data, int idx), void* data2, int count, int offset=0);
+// Plots a shaded (filled) region between two lines, or a line and a horizontal reference. Set yref to +/-INFINITY for infinite fill extents.
+IMPLOT_TMP void PlotShaded(const char* label_id, const T* values, int count, double yref=0, double xscale=1, double x0=0, int offset=0, int stride=sizeof(T));
+IMPLOT_TMP void PlotShaded(const char* label_id, const T* xs, const T* ys, int count, double yref=0, int offset=0, int stride=sizeof(T));
+IMPLOT_TMP void PlotShaded(const char* label_id, const T* xs, const T* ys1, const T* ys2, int count, int offset=0, int stride=sizeof(T));
+IMPLOT_API void PlotShadedG(const char* label_id, ImPlotGetter getter1, void* data1, ImPlotGetter getter2, void* data2, int count);
-// Plots a vertical bar graph. #width and #shift are in X units.
-template <typename T> IMPLOT_API void PlotBars(const char* label_id, const T* values, int count, double width=0.67, double shift=0, int offset=0, int stride=sizeof(T));
-template <typename T> IMPLOT_API void PlotBars(const char* label_id, const T* xs, const T* ys, int count, double width, int offset=0, int stride=sizeof(T));
- IMPLOT_API void PlotBarsG(const char* label_id, ImPlotPoint (*getter)(void* data, int idx), void* data, int count, double width, int offset=0);
+// Plots a vertical bar graph. #bar_width and #x0 are in X units.
+IMPLOT_TMP void PlotBars(const char* label_id, const T* values, int count, double bar_width=0.67, double x0=0, int offset=0, int stride=sizeof(T));
+IMPLOT_TMP void PlotBars(const char* label_id, const T* xs, const T* ys, int count, double bar_width, int offset=0, int stride=sizeof(T));
+IMPLOT_API void PlotBarsG(const char* label_id, ImPlotGetter getter, void* data, int count, double bar_width);
-// Plots a horizontal bar graph. #height and #shift are in Y units.
-template <typename T> IMPLOT_API void PlotBarsH(const char* label_id, const T* values, int count, double height=0.67, double shift=0, int offset=0, int stride=sizeof(T));
-template <typename T> IMPLOT_API void PlotBarsH(const char* label_id, const T* xs, const T* ys, int count, double height, int offset=0, int stride=sizeof(T));
- IMPLOT_API void PlotBarsHG(const char* label_id, ImPlotPoint (*getter)(void* data, int idx), void* data, int count, double height, int offset=0);
+// Plots a horizontal bar graph. #bar_height and #y0 are in Y units.
+IMPLOT_TMP void PlotBarsH(const char* label_id, const T* values, int count, double bar_height=0.67, double y0=0, int offset=0, int stride=sizeof(T));
+IMPLOT_TMP void PlotBarsH(const char* label_id, const T* xs, const T* ys, int count, double bar_height, int offset=0, int stride=sizeof(T));
+IMPLOT_API void PlotBarsHG(const char* label_id, ImPlotGetter getter, void* data, int count, double bar_height);
+
+// Plots a group of vertical bars. #values is a row-major matrix with #item_count rows and #group_count cols. #label_ids should have #item_count elements.
+IMPLOT_TMP void PlotBarGroups(const char* const label_ids[], const T* values, int item_count, int group_count, double group_width=0.67, double x0=0, ImPlotBarGroupsFlags flags=ImPlotBarGroupsFlags_None);
+
+// Plots a group of horizontal bars. #values is a row-major matrix with #item_count rows and #group_count cols. #label_ids should have #item_count elements.
+IMPLOT_TMP void PlotBarGroupsH(const char* const label_ids[], const T* values, int item_count, int group_count, double group_height=0.67, double y0=0, ImPlotBarGroupsFlags flags=ImPlotBarGroupsFlags_None);
// Plots vertical error bar. The label_id should be the same as the label_id of the associated line or bar plot.
-template <typename T> IMPLOT_API void PlotErrorBars(const char* label_id, const T* xs, const T* ys, const T* err, int count, int offset=0, int stride=sizeof(T));
-template <typename T> IMPLOT_API void PlotErrorBars(const char* label_id, const T* xs, const T* ys, const T* neg, const T* pos, int count, int offset=0, int stride=sizeof(T));
+IMPLOT_TMP void PlotErrorBars(const char* label_id, const T* xs, const T* ys, const T* err, int count, int offset=0, int stride=sizeof(T));
+IMPLOT_TMP void PlotErrorBars(const char* label_id, const T* xs, const T* ys, const T* neg, const T* pos, int count, int offset=0, int stride=sizeof(T));
// Plots horizontal error bars. The label_id should be the same as the label_id of the associated line or bar plot.
-template <typename T> IMPLOT_API void PlotErrorBarsH(const char* label_id, const T* xs, const T* ys, const T* err, int count, int offset=0, int stride=sizeof(T));
-template <typename T> IMPLOT_API void PlotErrorBarsH(const char* label_id, const T* xs, const T* ys, const T* neg, const T* pos, int count, int offset=0, int stride=sizeof(T));
+IMPLOT_TMP void PlotErrorBarsH(const char* label_id, const T* xs, const T* ys, const T* err, int count, int offset=0, int stride=sizeof(T));
+IMPLOT_TMP void PlotErrorBarsH(const char* label_id, const T* xs, const T* ys, const T* neg, const T* pos, int count, int offset=0, int stride=sizeof(T));
/// Plots vertical stems.
-template <typename T> IMPLOT_API void PlotStems(const char* label_id, const T* values, int count, double y_ref=0, double xscale=1, double x0=0, int offset=0, int stride=sizeof(T));
-template <typename T> IMPLOT_API void PlotStems(const char* label_id, const T* xs, const T* ys, int count, double y_ref=0, int offset=0, int stride=sizeof(T));
+IMPLOT_TMP void PlotStems(const char* label_id, const T* values, int count, double yref=0, double xscale=1, double x0=0, int offset=0, int stride=sizeof(T));
+IMPLOT_TMP void PlotStems(const char* label_id, const T* xs, const T* ys, int count, double yref=0, int offset=0, int stride=sizeof(T));
/// Plots infinite vertical or horizontal lines (e.g. for references or asymptotes).
-template <typename T> IMPLOT_API void PlotVLines(const char* label_id, const T* xs, int count, int offset=0, int stride=sizeof(T));
-template <typename T> IMPLOT_API void PlotHLines(const char* label_id, const T* ys, int count, int offset=0, int stride=sizeof(T));
+IMPLOT_TMP void PlotVLines(const char* label_id, const T* xs, int count, int offset=0, int stride=sizeof(T));
+IMPLOT_TMP void PlotHLines(const char* label_id, const T* ys, int count, int offset=0, int stride=sizeof(T));
// Plots a pie chart. If the sum of values > 1 or normalize is true, each value will be normalized. Center and radius are in plot units. #label_fmt can be set to NULL for no labels.
-template <typename T> IMPLOT_API void PlotPieChart(const char* const label_ids[], const T* values, int count, double x, double y, double radius, bool normalize=false, const char* label_fmt="%.1f", double angle0=90);
+IMPLOT_TMP void PlotPieChart(const char* const label_ids[], const T* values, int count, double x, double y, double radius, bool normalize=false, const char* label_fmt="%.1f", double angle0=90);
// Plots a 2D heatmap chart. Values are expected to be in row-major order. Leave #scale_min and scale_max both at 0 for automatic color scaling, or set them to a predefined range. #label_fmt can be set to NULL for no labels.
-template <typename T> IMPLOT_API void PlotHeatmap(const char* label_id, const T* values, int rows, int cols, double scale_min=0, double scale_max=0, const char* label_fmt="%.1f", const ImPlotPoint& bounds_min=ImPlotPoint(0,0), const ImPlotPoint& bounds_max=ImPlotPoint(1,1));
+IMPLOT_TMP void PlotHeatmap(const char* label_id, const T* values, int rows, int cols, double scale_min=0, double scale_max=0, const char* label_fmt="%.1f", const ImPlotPoint& bounds_min=ImPlotPoint(0,0), const ImPlotPoint& bounds_max=ImPlotPoint(1,1));
// Plots a horizontal histogram. #bins can be a positive integer or an ImPlotBin_ method. If #cumulative is true, each bin contains its count plus the counts of all previous bins.
// If #density is true, the PDF is visualized. If both are true, the CDF is visualized. If #range is left unspecified, the min/max of #values will be used as the range.
// If #range is specified, outlier values outside of the range are not binned. However, outliers still count toward normalizing and cumulative counts unless #outliers is false. The largest bin count or density is returned.
-template <typename T> IMPLOT_API double PlotHistogram(const char* label_id, const T* values, int count, int bins=ImPlotBin_Sturges, bool cumulative=false, bool density=false, ImPlotRange range=ImPlotRange(), bool outliers=true, double bar_scale=1.0);
+IMPLOT_TMP double PlotHistogram(const char* label_id, const T* values, int count, int bins=ImPlotBin_Sturges, bool cumulative=false, bool density=false, ImPlotRange range=ImPlotRange(), bool outliers=true, double bar_scale=1.0);
// Plots two dimensional, bivariate histogram as a heatmap. #x_bins and #y_bins can be a positive integer or an ImPlotBin. If #density is true, the PDF is visualized.
-// If #range is left unspecified, the min/max of #xs an #ys will be used as the ranges. If #range is specified, outlier values outside of range are not binned.
+// If #bounds is left unspecified, the min/max of #xs an #ys will be used as the ranges. If #bounds is specified, outlier values outside of range are not binned.
// However, outliers still count toward the normalizing count for density plots unless #outliers is false. The largest bin count or density is returned.
-template <typename T> IMPLOT_API double PlotHistogram2D(const char* label_id, const T* xs, const T* ys, int count, int x_bins=ImPlotBin_Sturges, int y_bins=ImPlotBin_Sturges, bool density=false, ImPlotLimits range=ImPlotLimits(), bool outliers=true);
+IMPLOT_TMP double PlotHistogram2D(const char* label_id, const T* xs, const T* ys, int count, int x_bins=ImPlotBin_Sturges, int y_bins=ImPlotBin_Sturges, bool density=false, ImPlotRect range=ImPlotRect(), bool outliers=true);
// Plots digital data. Digital plots do not respond to y drag or zoom, and are always referenced to the bottom of the plot.
-template <typename T> IMPLOT_API void PlotDigital(const char* label_id, const T* xs, const T* ys, int count, int offset=0, int stride=sizeof(T));
- IMPLOT_API void PlotDigitalG(const char* label_id, ImPlotPoint (*getter)(void* data, int idx), void* data, int count, int offset=0);
+IMPLOT_TMP void PlotDigital(const char* label_id, const T* xs, const T* ys, int count, int offset=0, int stride=sizeof(T));
+IMPLOT_API void PlotDigitalG(const char* label_id, ImPlotGetter getter, void* data, int count);
// Plots an axis-aligned image. #bounds_min/bounds_max are in plot coordinates (y-up) and #uv0/uv1 are in texture coordinates (y-down).
IMPLOT_API void PlotImage(const char* label_id, ImTextureID user_texture_id, const ImPlotPoint& bounds_min, const ImPlotPoint& bounds_max, const ImVec2& uv0=ImVec2(0,0), const ImVec2& uv1=ImVec2(1,1), const ImVec4& tint_col=ImVec4(1,1,1,1));
@@ -505,129 +769,111 @@ IMPLOT_API void PlotText(const char* text, double x, double y, bool vertical=fal
IMPLOT_API void PlotDummy(const char* label_id);
//-----------------------------------------------------------------------------
-// Plot Utils
+// [SECTION] Plot Tools
//-----------------------------------------------------------------------------
-// The following functions MUST be called BEFORE BeginPlot!
+// The following can be used to render interactive elements and/or annotations.
+// Like the item plotting functions above, they apply to the current x and y
+// axes, which can be changed with `SetAxis/SetAxes`.
-// Set the axes range limits of the next plot. Call right before BeginPlot(). If ImGuiCond_Always is used, the axes limits will be locked.
-IMPLOT_API void SetNextPlotLimits(double xmin, double xmax, double ymin, double ymax, ImGuiCond cond = ImGuiCond_Once);
-// Set the X axis range limits of the next plot. Call right before BeginPlot(). If ImGuiCond_Always is used, the X axis limits will be locked.
-IMPLOT_API void SetNextPlotLimitsX(double xmin, double xmax, ImGuiCond cond = ImGuiCond_Once);
-// Set the Y axis range limits of the next plot. Call right before BeginPlot(). If ImGuiCond_Always is used, the Y axis limits will be locked.
-IMPLOT_API void SetNextPlotLimitsY(double ymin, double ymax, ImGuiCond cond = ImGuiCond_Once, ImPlotYAxis y_axis = ImPlotYAxis_1);
-// Links the next plot limits to external values. Set to NULL for no linkage. The pointer data must remain valid until the matching call to EndPlot.
-IMPLOT_API void LinkNextPlotLimits(double* xmin, double* xmax, double* ymin, double* ymax, double* ymin2 = NULL, double* ymax2 = NULL, double* ymin3 = NULL, double* ymax3 = NULL);
-// Fits the next plot axes to all plotted data if they are unlocked (equivalent to double-clicks).
-IMPLOT_API void FitNextPlotAxes(bool x = true, bool y = true, bool y2 = true, bool y3 = true);
+// Shows a draggable point at x,y. #col defaults to ImGuiCol_Text.
+IMPLOT_API bool DragPoint(int id, double* x, double* y, const ImVec4& col, float size = 4, ImPlotDragToolFlags flags = ImPlotDragToolFlags_None);
+// Shows a draggable vertical guide line at an x-value. #col defaults to ImGuiCol_Text.
+IMPLOT_API bool DragLineX(int id, double* x, const ImVec4& col, float thickness = 1, ImPlotDragToolFlags flags = ImPlotDragToolFlags_None);
+// Shows a draggable horizontal guide line at a y-value. #col defaults to ImGuiCol_Text.
+IMPLOT_API bool DragLineY(int id, double* y, const ImVec4& col, float thickness = 1, ImPlotDragToolFlags flags = ImPlotDragToolFlags_None);
+// Shows a draggable and resizeable rectangle.
+IMPLOT_API bool DragRect(int id, double* x_min, double* y_min, double* x_max, double* y_max, const ImVec4& col, ImPlotDragToolFlags flags = ImPlotDragToolFlags_None);
+
+// Shows an annotation callout at a chosen point. Clamping keeps annotations in the plot area. Annotations are always rendered on top.
+IMPLOT_API void Annotation(double x, double y, const ImVec4& color, const ImVec2& pix_offset, bool clamp, bool round = false);
+IMPLOT_API void Annotation(double x, double y, const ImVec4& color, const ImVec2& pix_offset, bool clamp, const char* fmt, ...) IM_FMTARGS(6);
+IMPLOT_API void AnnotationV(double x, double y, const ImVec4& color, const ImVec2& pix_offset, bool clamp, const char* fmt, va_list args) IM_FMTLIST(6);
+
+// Shows a x-axis tag at the specified coordinate value.
+IMPLOT_API void TagX(double x, const ImVec4& color, bool round = false);
+IMPLOT_API void TagX(double x, const ImVec4& color, const char* fmt, ...) IM_FMTARGS(3);
+IMPLOT_API void TagXV(double x, const ImVec4& color, const char* fmt, va_list args) IM_FMTLIST(3);
+
+// Shows a y-axis tag at the specified coordinate value.
+IMPLOT_API void TagY(double y, const ImVec4& color, bool round = false);
+IMPLOT_API void TagY(double y, const ImVec4& color, const char* fmt, ...) IM_FMTARGS(3);
+IMPLOT_API void TagYV(double y, const ImVec4& color, const char* fmt, va_list args) IM_FMTLIST(3);
-// Set the X axis ticks and optionally the labels for the next plot. To keep the default ticks, set #keep_default=true.
-IMPLOT_API void SetNextPlotTicksX(const double* values, int n_ticks, const char* const labels[] = NULL, bool keep_default = false);
-IMPLOT_API void SetNextPlotTicksX(double x_min, double x_max, int n_ticks, const char* const labels[] = NULL, bool keep_default = false);
-// Set the Y axis ticks and optionally the labels for the next plot. To keep the default ticks, set #keep_default=true.
-IMPLOT_API void SetNextPlotTicksY(const double* values, int n_ticks, const char* const labels[] = NULL, bool keep_default = false, ImPlotYAxis y_axis = ImPlotYAxis_1);
-IMPLOT_API void SetNextPlotTicksY(double y_min, double y_max, int n_ticks, const char* const labels[] = NULL, bool keep_default = false, ImPlotYAxis y_axis = ImPlotYAxis_1);
+//-----------------------------------------------------------------------------
+// [SECTION] Plot Utils
+//-----------------------------------------------------------------------------
-// Set the format for numeric X axis labels (default="%g"). Formated values will be doubles (i.e. don't supply %d, %i, etc.). Not applicable if ImPlotAxisFlags_Time enabled.
-IMPLOT_API void SetNextPlotFormatX(const char* fmt);
-// Set the format for numeric Y axis labels (default="%g"). Formated values will be doubles (i.e. don't supply %d, %i, etc.).
-IMPLOT_API void SetNextPlotFormatY(const char* fmt, ImPlotYAxis y_axis=ImPlotYAxis_1);
+// Select which axis/axes will be used for subsequent plot elements.
+IMPLOT_API void SetAxis(ImAxis axis);
+IMPLOT_API void SetAxes(ImAxis x_axis, ImAxis y_axis);
-// The following functions MUST be called BETWEEN Begin/EndPlot!
+// Convert pixels to a position in the current plot's coordinate system. Passing IMPLOT_AUTO uses the current axes.
+IMPLOT_API ImPlotPoint PixelsToPlot(const ImVec2& pix, ImAxis x_axis = IMPLOT_AUTO, ImAxis y_axis = IMPLOT_AUTO);
+IMPLOT_API ImPlotPoint PixelsToPlot(float x, float y, ImAxis x_axis = IMPLOT_AUTO, ImAxis y_axis = IMPLOT_AUTO);
-// Select which Y axis will be used for subsequent plot elements. The default is ImPlotYAxis_1, or the first (left) Y axis. Enable 2nd and 3rd axes with ImPlotFlags_YAxisX.
-IMPLOT_API void SetPlotYAxis(ImPlotYAxis y_axis);
-// Hides or shows the next plot item (i.e. as if it were toggled from the legend). Use ImGuiCond_Always if you need to forcefully set this every frame.
-IMPLOT_API void HideNextItem(bool hidden = true, ImGuiCond cond = ImGuiCond_Once);
+// Convert a position in the current plot's coordinate system to pixels. Passing IMPLOT_AUTO uses the current axes.
+IMPLOT_API ImVec2 PlotToPixels(const ImPlotPoint& plt, ImAxis x_axis = IMPLOT_AUTO, ImAxis y_axis = IMPLOT_AUTO);
+IMPLOT_API ImVec2 PlotToPixels(double x, double y, ImAxis x_axis = IMPLOT_AUTO, ImAxis y_axis = IMPLOT_AUTO);
-// Convert pixels to a position in the current plot's coordinate system. A negative y_axis uses the current value of SetPlotYAxis (ImPlotYAxis_1 initially).
-IMPLOT_API ImPlotPoint PixelsToPlot(const ImVec2& pix, ImPlotYAxis y_axis = IMPLOT_AUTO);
-IMPLOT_API ImPlotPoint PixelsToPlot(float x, float y, ImPlotYAxis y_axis = IMPLOT_AUTO);
-// Convert a position in the current plot's coordinate system to pixels. A negative y_axis uses the current value of SetPlotYAxis (ImPlotYAxis_1 initially).
-IMPLOT_API ImVec2 PlotToPixels(const ImPlotPoint& plt, ImPlotYAxis y_axis = IMPLOT_AUTO);
-IMPLOT_API ImVec2 PlotToPixels(double x, double y, ImPlotYAxis y_axis = IMPLOT_AUTO);
// Get the current Plot position (top-left) in pixels.
IMPLOT_API ImVec2 GetPlotPos();
// Get the curent Plot size in pixels.
IMPLOT_API ImVec2 GetPlotSize();
+
+// Returns the mouse position in x,y coordinates of the current plot. Passing IMPLOT_AUTO uses the current axes.
+IMPLOT_API ImPlotPoint GetPlotMousePos(ImAxis x_axis = IMPLOT_AUTO, ImAxis y_axis = IMPLOT_AUTO);
+// Returns the current plot axis range.
+IMPLOT_API ImPlotRect GetPlotLimits(ImAxis x_axis = IMPLOT_AUTO, ImAxis y_axis = IMPLOT_AUTO);
+
// Returns true if the plot area in the current plot is hovered.
IMPLOT_API bool IsPlotHovered();
-// Returns true if the XAxis plot area in the current plot is hovered.
-IMPLOT_API bool IsPlotXAxisHovered();
-// Returns true if the YAxis[n] plot area in the current plot is hovered.
-IMPLOT_API bool IsPlotYAxisHovered(ImPlotYAxis y_axis = 0);
-// Returns the mouse position in x,y coordinates of the current plot. A negative y_axis uses the current value of SetPlotYAxis (ImPlotYAxis_1 initially).
-IMPLOT_API ImPlotPoint GetPlotMousePos(ImPlotYAxis y_axis = IMPLOT_AUTO);
-// Returns the current plot axis range. A negative y_axis uses the current value of SetPlotYAxis (ImPlotYAxis_1 initially).
-IMPLOT_API ImPlotLimits GetPlotLimits(ImPlotYAxis y_axis = IMPLOT_AUTO);
+// Returns true if the axis label area in the current plot is hovered.
+IMPLOT_API bool IsAxisHovered(ImAxis axis);
+// Returns true if the bounding frame of a subplot is hovered.
+IMPLOT_API bool IsSubplotsHovered();
// Returns true if the current plot is being box selected.
IMPLOT_API bool IsPlotSelected();
-// Returns the current plot box selection bounds.
-IMPLOT_API ImPlotLimits GetPlotSelection(ImPlotYAxis y_axis = IMPLOT_AUTO);
+// Returns the current plot box selection bounds. Passing IMPLOT_AUTO uses the current axes.
+IMPLOT_API ImPlotRect GetPlotSelection(ImAxis x_axis = IMPLOT_AUTO, ImAxis y_axis = IMPLOT_AUTO);
+// Cancels a the current plot box selection.
+IMPLOT_API void CancelPlotSelection();
-// Returns true if the current plot is being queried or has an active query. Query must be enabled with ImPlotFlags_Query.
-IMPLOT_API bool IsPlotQueried();
-// Returns the current plot query bounds. Query must be enabled with ImPlotFlags_Query.
-IMPLOT_API ImPlotLimits GetPlotQuery(ImPlotYAxis y_axis = IMPLOT_AUTO);
-// Set the current plot query bounds. Query must be enabled with ImPlotFlags_Query.
-IMPLOT_API void SetPlotQuery(const ImPlotLimits& query, ImPlotYAxis y_axis = IMPLOT_AUTO);
+// Hides or shows the next plot item (i.e. as if it were toggled from the legend).
+// Use ImPlotCond_Always if you need to forcefully set this every frame.
+IMPLOT_API void HideNextItem(bool hidden = true, ImPlotCond cond = ImPlotCond_Once);
-//-----------------------------------------------------------------------------
-// Plot Tools
-//-----------------------------------------------------------------------------
-
-// The following functions MUST be called BETWEEN Begin/EndPlot!
-
-// Shows an annotation callout at a chosen point.
-IMPLOT_API void Annotate(double x, double y, const ImVec2& pix_offset, const char* fmt, ...) IM_FMTARGS(4);
-IMPLOT_API void Annotate(double x, double y, const ImVec2& pix_offset, const ImVec4& color, const char* fmt, ...) IM_FMTARGS(5);
-IMPLOT_API void AnnotateV(double x, double y, const ImVec2& pix_offset, const char* fmt, va_list args) IM_FMTLIST(4);
-IMPLOT_API void AnnotateV(double x, double y, const ImVec2& pix_offset, const ImVec4& color, const char* fmt, va_list args) IM_FMTLIST(5);
+// Use the following around calls to Begin/EndPlot to align l/r/t/b padding.
+// Consider using Begin/EndSubplots first. They are more feature rich and
+// accomplish the same behaviour by default. The functions below offer lower
+// level control of plot alignment.
-// Same as above, but the annotation will always be clamped to stay inside the plot area.
-IMPLOT_API void AnnotateClamped(double x, double y, const ImVec2& pix_offset, const char* fmt, ...) IM_FMTARGS(4);
-IMPLOT_API void AnnotateClamped(double x, double y, const ImVec2& pix_offset, const ImVec4& color, const char* fmt, ...) IM_FMTARGS(5);
-IMPLOT_API void AnnotateClampedV(double x, double y, const ImVec2& pix_offset, const char* fmt, va_list args) IM_FMTLIST(4);
-IMPLOT_API void AnnotateClampedV(double x, double y, const ImVec2& pix_offset, const ImVec4& color, const char* fmt, va_list args) IM_FMTLIST(5);
-
-// Shows a draggable vertical guide line at an x-value. #col defaults to ImGuiCol_Text.
-IMPLOT_API bool DragLineX(const char* id, double* x_value, bool show_label = true, const ImVec4& col = IMPLOT_AUTO_COL, float thickness = 1);
-// Shows a draggable horizontal guide line at a y-value. #col defaults to ImGuiCol_Text.
-IMPLOT_API bool DragLineY(const char* id, double* y_value, bool show_label = true, const ImVec4& col = IMPLOT_AUTO_COL, float thickness = 1);
-// Shows a draggable point at x,y. #col defaults to ImGuiCol_Text.
-IMPLOT_API bool DragPoint(const char* id, double* x, double* y, bool show_label = true, const ImVec4& col = IMPLOT_AUTO_COL, float radius = 4);
+// Align axis padding over multiple plots in a single row or column. #group_id must
+// be unique. If this function returns true, EndAlignedPlots() must be called.
+IMPLOT_API bool BeginAlignedPlots(const char* group_id, bool vertical = true);
+// Only call EndAlignedPlots() if BeginAlignedPlots() returns true!
+IMPLOT_API void EndAlignedPlots();
//-----------------------------------------------------------------------------
-// Legend Utils and Tools
+// [SECTION] Legend Utils
//-----------------------------------------------------------------------------
-// The following functions MUST be called BETWEEN Begin/EndPlot!
-
-// Set the location of the current plot's legend (default = North|West).
-IMPLOT_API void SetLegendLocation(ImPlotLocation location, ImPlotOrientation orientation = ImPlotOrientation_Vertical, bool outside = false);
-// Set the location of the current plot's mouse position text (default = South|East).
-IMPLOT_API void SetMousePosLocation(ImPlotLocation location);
-// Returns true if a plot item legend entry is hovered.
-IMPLOT_API bool IsLegendEntryHovered(const char* label_id);
-
// Begin a popup for a legend entry.
IMPLOT_API bool BeginLegendPopup(const char* label_id, ImGuiMouseButton mouse_button = 1);
// End a popup for a legend entry.
IMPLOT_API void EndLegendPopup();
+// Returns true if a plot item legend entry is hovered.
+IMPLOT_API bool IsLegendEntryHovered(const char* label_id);
//-----------------------------------------------------------------------------
-// Drag and Drop Utils
+// [SECTION] Drag and Drop
//-----------------------------------------------------------------------------
-// The following functions MUST be called BETWEEN Begin/EndPlot!
-
// Turns the current plot's plotting area into a drag and drop target. Don't forget to call EndDragDropTarget!
-IMPLOT_API bool BeginDragDropTarget();
+IMPLOT_API bool BeginDragDropTargetPlot();
// Turns the current plot's X-axis into a drag and drop target. Don't forget to call EndDragDropTarget!
-IMPLOT_API bool BeginDragDropTargetX();
-// Turns the current plot's Y-Axis into a drag and drop target. Don't forget to call EndDragDropTarget!
-IMPLOT_API bool BeginDragDropTargetY(ImPlotYAxis axis = ImPlotYAxis_1);
+IMPLOT_API bool BeginDragDropTargetAxis(ImAxis axis);
// Turns the current plot's legend into a drag and drop target. Don't forget to call EndDragDropTarget!
IMPLOT_API bool BeginDragDropTargetLegend();
// Ends a drag and drop target (currently just an alias for ImGui::EndDragDropTarget).
@@ -636,19 +882,17 @@ IMPLOT_API void EndDragDropTarget();
// NB: By default, plot and axes drag and drop *sources* require holding the Ctrl modifier to initiate the drag.
// You can change the modifier if desired. If ImGuiKeyModFlags_None is provided, the axes will be locked from panning.
-// Turns the current plot's plotting area into a drag and drop source. Don't forget to call EndDragDropSource!
-IMPLOT_API bool BeginDragDropSource(ImGuiKeyModFlags key_mods = ImGuiKeyModFlags_Ctrl, ImGuiDragDropFlags flags = 0);
-// Turns the current plot's X-axis into a drag and drop source. Don't forget to call EndDragDropSource!
-IMPLOT_API bool BeginDragDropSourceX(ImGuiKeyModFlags key_mods = ImGuiKeyModFlags_Ctrl, ImGuiDragDropFlags flags = 0);
-// Turns the current plot's Y-axis into a drag and drop source. Don't forget to call EndDragDropSource!
-IMPLOT_API bool BeginDragDropSourceY(ImPlotYAxis axis = ImPlotYAxis_1, ImGuiKeyModFlags key_mods = ImGuiKeyModFlags_Ctrl, ImGuiDragDropFlags flags = 0);
+// Turns the current plot's plotting area into a drag and drop source. You must hold Ctrl. Don't forget to call EndDragDropSource!
+IMPLOT_API bool BeginDragDropSourcePlot(ImGuiDragDropFlags flags = 0);
+// Turns the current plot's X-axis into a drag and drop source. You must hold Ctrl. Don't forget to call EndDragDropSource!
+IMPLOT_API bool BeginDragDropSourceAxis(ImAxis axis, ImGuiDragDropFlags flags = 0);
// Turns an item in the current plot's legend into drag and drop source. Don't forget to call EndDragDropSource!
IMPLOT_API bool BeginDragDropSourceItem(const char* label_id, ImGuiDragDropFlags flags = 0);
// Ends a drag and drop source (currently just an alias for ImGui::EndDragDropSource).
IMPLOT_API void EndDragDropSource();
//-----------------------------------------------------------------------------
-// Plot and Item Styling
+// [SECTION] Styling
//-----------------------------------------------------------------------------
// Styling colors in ImPlot works similarly to styling colors in ImGui, but
@@ -734,7 +978,7 @@ IMPLOT_API const char* GetStyleColorName(ImPlotCol idx);
IMPLOT_API const char* GetMarkerName(ImPlotMarker idx);
//-----------------------------------------------------------------------------
-// Colormaps
+// [SECTION] Colormaps
//-----------------------------------------------------------------------------
// Item styling is based on colormaps when the relevant ImPlotCol_XXX is set to
@@ -784,7 +1028,7 @@ IMPLOT_API ImVec4 GetColormapColor(int idx, ImPlotColormap cmap = IMPLOT_AUTO);
IMPLOT_API ImVec4 SampleColormap(float t, ImPlotColormap cmap = IMPLOT_AUTO);
// Shows a vertical color scale with linear spaced ticks using the specified color map. Use double hashes to hide label (e.g. "##NoLabel").
-IMPLOT_API void ColormapScale(const char* label, double scale_min, double scale_max, const ImVec2& size = ImVec2(0,0), ImPlotColormap cmap = IMPLOT_AUTO, const char* fmt = "%g");
+IMPLOT_API void ColormapScale(const char* label, double scale_min, double scale_max, const ImVec2& size = ImVec2(0,0), ImPlotColormap cmap = IMPLOT_AUTO, const char* format = "%g");
// Shows a horizontal slider with a colormap gradient background. Optionally returns the color sampled at t in [0 1].
IMPLOT_API bool ColormapSlider(const char* label, float* t, ImVec4* out = NULL, const char* format = "", ImPlotColormap cmap = IMPLOT_AUTO);
// Shows a button with a colormap gradient brackground.
@@ -800,7 +1044,19 @@ IMPLOT_API bool ColormapButton(const char* label, const ImVec2& size = ImVec2(0,
IMPLOT_API void BustColorCache(const char* plot_title_id = NULL);
//-----------------------------------------------------------------------------
-// Miscellaneous
+// [SECTION] Input Mapping
+//-----------------------------------------------------------------------------
+
+// Provides access to input mapping structure for permanant modifications to controls for pan, select, etc.
+IMPLOT_API ImPlotInputMap& GetInputMap();
+
+// Default input mapping: pan = LMB drag, box select = RMB drag, fit = LMB double click, context menu = RMB click, zoom = scroll.
+IMPLOT_API void MapInputDefault(ImPlotInputMap* dst = NULL);
+// Reverse input mapping: pan = RMB drag, box select = LMB drag, fit = LMB double click, context menu = RMB click, zoom = scroll.
+IMPLOT_API void MapInputReverse(ImPlotInputMap* dst = NULL);
+
+//-----------------------------------------------------------------------------
+// [SECTION] Miscellaneous
//-----------------------------------------------------------------------------
// Render icons similar to those that appear in legends (nifty for data lists).
@@ -819,6 +1075,8 @@ IMPLOT_API void PopPlotClipRect();
IMPLOT_API bool ShowStyleSelector(const char* label);
// Shows ImPlot colormap selector dropdown menu.
IMPLOT_API bool ShowColormapSelector(const char* label);
+// Shows ImPlot input map selector dropdown menu.
+IMPLOT_API bool ShowInputMapSelector(const char* label);
// Shows ImPlot style editor block (not a window).
IMPLOT_API void ShowStyleEditor(ImPlotStyle* ref = NULL);
// Add basic help/info block for end users (not a window).
@@ -827,10 +1085,59 @@ IMPLOT_API void ShowUserGuide();
IMPLOT_API void ShowMetricsWindow(bool* p_popen = NULL);
//-----------------------------------------------------------------------------
-// Demo (add implot_demo.cpp to your sources!)
+// [SECTION] Demo
//-----------------------------------------------------------------------------
-// Shows the ImPlot demo window.
+// Shows the ImPlot demo window (add implot_demo.cpp to your sources!)
IMPLOT_API void ShowDemoWindow(bool* p_open = NULL);
} // namespace ImPlot
+
+//-----------------------------------------------------------------------------
+// [SECTION] Obsolete API
+//-----------------------------------------------------------------------------
+
+// The following functions will be removed! Keep your copy of implot up to date!
+// Occasionally set '#define IMPLOT_DISABLE_OBSOLETE_FUNCTIONS' to stay ahead.
+// If you absolutely must use these functions and do not want to receive compiler
+// warnings, set '#define IMPLOT_DISABLE_OBSOLETE_WARNINGS'.
+
+#ifndef IMPLOT_DISABLE_OBSOLETE_FUNCTIONS
+
+#ifndef IMPLOT_DISABLE_DEPRECATED_WARNINGS
+#if __cplusplus > 201402L
+#define IMPLOT_DEPRECATED(method) [[deprecated]] method
+#elif defined( __GNUC__ ) && !defined( __INTEL_COMPILER ) && ( __GNUC__ > 3 || ( __GNUC__ == 3 && __GNUC_MINOR__ >= 1 ) )
+#define IMPLOT_DEPRECATED(method) method __attribute__( ( deprecated ) )
+#elif defined( _MSC_VER )
+#define IMPLOT_DEPRECATED(method) __declspec(deprecated) method
+#else
+#define IMPLOT_DEPRECATED(method) method
+#endif
+#else
+#define IMPLOT_DEPRECATED(method) method
+#endif
+
+enum ImPlotFlagsObsolete_ {
+ ImPlotFlags_YAxis2 = 1 << 20,
+ ImPlotFlags_YAxis3 = 1 << 21,
+};
+
+namespace ImPlot {
+
+// OBSOLETED in v0.13 -> PLANNED REMOVAL in v1.0
+IMPLOT_DEPRECATED( IMPLOT_API bool BeginPlot(const char* title_id,
+ const char* x_label, // = NULL,
+ const char* y_label, // = NULL,
+ const ImVec2& size = ImVec2(-1,0),
+ ImPlotFlags flags = ImPlotFlags_None,
+ ImPlotAxisFlags x_flags = ImPlotAxisFlags_None,
+ ImPlotAxisFlags y_flags = ImPlotAxisFlags_None,
+ ImPlotAxisFlags y2_flags = ImPlotAxisFlags_AuxDefault,
+ ImPlotAxisFlags y3_flags = ImPlotAxisFlags_AuxDefault,
+ const char* y2_label = NULL,
+ const char* y3_label = NULL) );
+
+} // namespace ImPlot
+
+#endif
diff --git a/3rdparty/implot/implot_demo.cpp b/3rdparty/implot/implot_demo.cpp
index 53989df..be1548c 100644
--- a/3rdparty/implot/implot_demo.cpp
+++ b/3rdparty/implot/implot_demo.cpp
@@ -20,7 +20,10 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
-// ImPlot v0.10 WIP
+// ImPlot v0.13 WIP
+
+// We define this so that the demo does not accidentally use deprecated API
+#define IMPLOT_DISABLE_OBSOLETE_FUNCTIONS
#include "implot.h"
#include <math.h>
@@ -174,1424 +177,1937 @@ struct HugeTimeData {
static const int Size = 60*60*24*366;
};
-void ShowDemoWindow(bool* p_open) {
- double DEMO_TIME = ImGui::GetTime();
- static bool show_imgui_metrics = false;
- static bool show_implot_metrics = false;
- static bool show_imgui_style_editor = false;
- static bool show_implot_style_editor = false;
- static bool show_implot_benchmark = false;
- if (show_imgui_metrics) {
- ImGui::ShowMetricsWindow(&show_imgui_metrics);
+//-----------------------------------------------------------------------------
+// [SECTION] Demo Functions
+//-----------------------------------------------------------------------------
+
+void ShowDemo_Help() {
+ ImGui::Text("ABOUT THIS DEMO:");
+ ImGui::BulletText("Sections below are demonstrating many aspects of the library.");
+ ImGui::BulletText("The \"Tools\" menu above gives access to: Style Editors (ImPlot/ImGui)\n"
+ "and Metrics (general purpose Dear ImGui debugging tool).");
+ ImGui::Separator();
+ ImGui::Text("PROGRAMMER GUIDE:");
+ ImGui::BulletText("See the ShowDemoWindow() code in implot_demo.cpp. <- you are here!");
+ ImGui::BulletText("By default, anti-aliased lines are turned OFF.");
+ ImGui::Indent();
+ ImGui::BulletText("Software AA can be enabled globally with ImPlotStyle.AntiAliasedLines.");
+ ImGui::BulletText("Software AA can be enabled per plot with ImPlotFlags_AntiAliased.");
+ ImGui::BulletText("AA for plots can be toggled from the plot's context menu.");
+ ImGui::BulletText("If permitable, you are better off using hardware AA (e.g. MSAA).");
+ ImGui::Unindent();
+ ImGui::BulletText("If you see visual artifacts, do one of the following:");
+ ImGui::Indent();
+ ImGui::BulletText("Handle ImGuiBackendFlags_RendererHasVtxOffset for 16-bit indices in your backend.");
+ ImGui::BulletText("Or, enable 32-bit indices in imconfig.h.");
+ ImGui::BulletText("Your current configuration is:");
+ ImGui::Indent();
+ ImGui::BulletText("ImDrawIdx: %d-bit", (int)(sizeof(ImDrawIdx) * 8));
+ ImGui::BulletText("ImGuiBackendFlags_RendererHasVtxOffset: %s", (ImGui::GetIO().BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset) ? "True" : "False");
+ ImGui::Unindent();
+ ImGui::Unindent();
+ ImGui::Separator();
+ ImGui::Text("USER GUIDE:");
+ ShowUserGuide();
+}
+
+//-----------------------------------------------------------------------------
+
+void ButtonSelector(const char* label, ImGuiMouseButton* b) {
+ ImGui::PushID(label);
+ if (ImGui::RadioButton("LMB",*b == ImGuiMouseButton_Left))
+ *b = ImGuiMouseButton_Left;
+ ImGui::SameLine();
+ if (ImGui::RadioButton("RMB",*b == ImGuiMouseButton_Right))
+ *b = ImGuiMouseButton_Right;
+ ImGui::SameLine();
+ if (ImGui::RadioButton("MMB",*b == ImGuiMouseButton_Middle))
+ *b = ImGuiMouseButton_Middle;
+ ImGui::PopID();
+}
+
+void ModSelector(const char* label, ImGuiKeyModFlags* k) {
+ ImGui::PushID(label);
+ ImGui::CheckboxFlags("Ctrl", (unsigned int*)k, ImGuiKeyModFlags_Ctrl); ImGui::SameLine();
+ ImGui::CheckboxFlags("Shift", (unsigned int*)k, ImGuiKeyModFlags_Shift); ImGui::SameLine();
+ ImGui::CheckboxFlags("Alt", (unsigned int*)k, ImGuiKeyModFlags_Alt); ImGui::SameLine();
+ ImGui::CheckboxFlags("Super", (unsigned int*)k, ImGuiKeyModFlags_Super);
+ ImGui::PopID();
+}
+
+void InputMapping(const char* label, ImGuiMouseButton* b, ImGuiKeyModFlags* k) {
+ ImGui::LabelText("##","%s",label);
+ if (b != NULL) {
+ ImGui::SameLine(100);
+ ButtonSelector(label,b);
}
- if (show_implot_metrics) {
- ImPlot::ShowMetricsWindow(&show_implot_metrics);
+ if (k != NULL) {
+ ImGui::SameLine(300);
+ ModSelector(label,k);
}
- if (show_imgui_style_editor) {
- ImGui::Begin("Style Editor (ImGui)", &show_imgui_style_editor);
- ImGui::ShowStyleEditor();
- ImGui::End();
+}
+
+void ShowInputMapping() {
+ ImPlotInputMap& map = ImPlot::GetInputMap();
+ InputMapping("Pan",&map.Pan,&map.PanMod);
+ InputMapping("Fit",&map.Fit,NULL);
+ InputMapping("Select",&map.Select,&map.SelectMod);
+ InputMapping("SelectHorzMod",NULL,&map.SelectHorzMod);
+ InputMapping("SelectVertMod",NULL,&map.SelectVertMod);
+ InputMapping("SelectCancel",&map.SelectCancel,NULL);
+ InputMapping("Menu",&map.Menu,NULL);
+ InputMapping("OverrideMod",NULL,&map.OverrideMod);
+ InputMapping("ZoomMod",NULL,&map.ZoomMod);
+ ImGui::SliderFloat("ZoomRate",&map.ZoomRate,-1,1);
+}
+
+void ShowDemo_Config() {
+ ImGui::ShowFontSelector("Font");
+ ImGui::ShowStyleSelector("ImGui Style");
+ ImPlot::ShowStyleSelector("ImPlot Style");
+ ImPlot::ShowColormapSelector("ImPlot Colormap");
+ ImPlot::ShowInputMapSelector("Input Map");
+ ImGui::Separator();
+ ImGui::Checkbox("Anti-Aliased Lines", &ImPlot::GetStyle().AntiAliasedLines);
+ ImGui::Checkbox("Use Local Time", &ImPlot::GetStyle().UseLocalTime);
+ ImGui::Checkbox("Use ISO 8601", &ImPlot::GetStyle().UseISO8601);
+ ImGui::Checkbox("Use 24 Hour Clock", &ImPlot::GetStyle().Use24HourClock);
+ ImGui::Separator();
+ if (ImPlot::BeginPlot("Preview")) {
+ static double now = (double)time(0);
+ ImPlot::SetupAxis(ImAxis_X1,NULL,ImPlotAxisFlags_Time);
+ ImPlot::SetupAxisLimits(ImAxis_X1, now, now + 24*3600);
+ for (int i = 0; i < 10; ++i) {
+ double x[2] = {now, now + 24*3600};
+ double y[2] = {0,i/9.0};
+ ImGui::PushID(i);
+ ImPlot::PlotLine("##Line",x,y,2);
+ ImGui::PopID();
+ }
+ ImPlot::EndPlot();
}
- if (show_implot_style_editor) {
- ImGui::SetNextWindowSize(ImVec2(415,762), ImGuiCond_Appearing);
- ImGui::Begin("Style Editor (ImPlot)", &show_implot_style_editor);
- ImPlot::ShowStyleEditor();
- ImGui::End();
+}
+
+//-----------------------------------------------------------------------------
+
+void ShowDemo_LinePlots() {
+ static float xs1[1001], ys1[1001];
+ for (int i = 0; i < 1001; ++i) {
+ xs1[i] = i * 0.001f;
+ ys1[i] = 0.5f + 0.5f * sinf(50 * (xs1[i] + (float)ImGui::GetTime() / 10));
}
- if (show_implot_benchmark) {
- ImGui::SetNextWindowSize(ImVec2(530,740), ImGuiCond_Appearing);
- ImGui::Begin("ImPlot Benchmark Tool", &show_implot_benchmark);
- ImPlot::ShowBenchmarkTool();
- ImGui::End();
- return;
+ static double xs2[11], ys2[11];
+ for (int i = 0; i < 11; ++i) {
+ xs2[i] = i * 0.1f;
+ ys2[i] = xs2[i] * xs2[i];
}
- ImGui::SetNextWindowPos(ImVec2(50, 50), ImGuiCond_FirstUseEver);
- ImGui::SetNextWindowSize(ImVec2(600, 750), ImGuiCond_FirstUseEver);
- ImGui::Begin("ImPlot Demo", p_open, ImGuiWindowFlags_MenuBar);
- if (ImGui::BeginMenuBar()) {
- if (ImGui::BeginMenu("Tools")) {
- ImGui::MenuItem("Metrics (ImGui)", NULL, &show_imgui_metrics);
- ImGui::MenuItem("Metrics (ImPlot)", NULL, &show_implot_metrics);
- ImGui::MenuItem("Style Editor (ImGui)", NULL, &show_imgui_style_editor);
- ImGui::MenuItem("Style Editor (ImPlot)", NULL, &show_implot_style_editor);
- ImGui::MenuItem("Benchmark", NULL, &show_implot_benchmark);
- ImGui::EndMenu();
- }
- ImGui::EndMenuBar();
+ ImGui::BulletText("Anti-aliasing can be enabled from the plot's context menu (see Help).");
+ if (ImPlot::BeginPlot("Line Plot")) {
+ ImPlot::SetupAxes("x","f(x)");
+ ImPlot::PlotLine("sin(x)", xs1, ys1, 1001);
+ ImPlot::SetNextMarkerStyle(ImPlotMarker_Circle);
+ ImPlot::PlotLine("x^2", xs2, ys2, 11);
+ ImPlot::EndPlot();
}
- //-------------------------------------------------------------------------
- ImGui::Text("ImPlot says hello. (%s)", IMPLOT_VERSION);
- ImGui::Spacing();
+}
- if (ImGui::CollapsingHeader("Help")) {
- ImGui::Text("ABOUT THIS DEMO:");
- ImGui::BulletText("Sections below are demonstrating many aspects of the library.");
- ImGui::BulletText("The \"Tools\" menu above gives access to: Style Editors (ImPlot/ImGui)\n"
- "and Metrics (general purpose Dear ImGui debugging tool).");
- ImGui::Separator();
- ImGui::Text("PROGRAMMER GUIDE:");
- ImGui::BulletText("See the ShowDemoWindow() code in implot_demo.cpp. <- you are here!");
- ImGui::BulletText("By default, anti-aliased lines are turned OFF.");
- ImGui::Indent();
- ImGui::BulletText("Software AA can be enabled globally with ImPlotStyle.AntiAliasedLines.");
- ImGui::BulletText("Software AA can be enabled per plot with ImPlotFlags_AntiAliased.");
- ImGui::BulletText("AA for plots can be toggled from the plot's context menu.");
- ImGui::BulletText("If permitable, you are better off using hardware AA (e.g. MSAA).");
- ImGui::Unindent();
- ImGui::BulletText("If you see visual artifacts, do one of the following:");
- ImGui::Indent();
- ImGui::BulletText("Handle ImGuiBackendFlags_RendererHasVtxOffset for 16-bit indices in your backend.");
- ImGui::BulletText("Or, enable 32-bit indices in imconfig.h.");
- ImGui::BulletText("Your current configuration is:");
- ImGui::Indent();
- ImGui::BulletText("ImDrawIdx: %d-bit", (int)(sizeof(ImDrawIdx) * 8));
- ImGui::BulletText("ImGuiBackendFlags_RendererHasVtxOffset: %s", (ImGui::GetIO().BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset) ? "True" : "False");
- ImGui::Unindent();
- ImGui::Unindent();
- ImGui::Separator();
- ImGui::Text("USER GUIDE:");
- ShowUserGuide();
- }
- //-------------------------------------------------------------------------
- if (ImGui::CollapsingHeader("Configuration")) {
- ImGui::ShowFontSelector("Font");
- ImGui::ShowStyleSelector("ImGui Style");
- ImPlot::ShowStyleSelector("ImPlot Style");
- ImPlot::ShowColormapSelector("ImPlot Colormap");
- float indent = ImGui::CalcItemWidth() - ImGui::GetFrameHeight();
- ImGui::Indent(ImGui::CalcItemWidth() - ImGui::GetFrameHeight());
- ImGui::Checkbox("Anti-Aliased Lines", &ImPlot::GetStyle().AntiAliasedLines);
- ImGui::Unindent(indent);
+//-----------------------------------------------------------------------------
+
+void ShowDemo_FilledLinePlots() {
+ static double xs1[101], ys1[101], ys2[101], ys3[101];
+ srand(0);
+ for (int i = 0; i < 101; ++i) {
+ xs1[i] = (float)i;
+ ys1[i] = RandomRange(400.0,450.0);
+ ys2[i] = RandomRange(275.0,350.0);
+ ys3[i] = RandomRange(150.0,225.0);
}
- //-------------------------------------------------------------------------
- if (ImGui::CollapsingHeader("Line Plots")) {
- static float xs1[1001], ys1[1001];
- for (int i = 0; i < 1001; ++i) {
- xs1[i] = i * 0.001f;
- ys1[i] = 0.5f + 0.5f * sinf(50 * (xs1[i] + (float)DEMO_TIME / 10));
- }
- static double xs2[11], ys2[11];
- for (int i = 0; i < 11; ++i) {
- xs2[i] = i * 0.1f;
- ys2[i] = xs2[i] * xs2[i];
- }
- ImGui::BulletText("Anti-aliasing can be enabled from the plot's context menu (see Help).");
- if (ImPlot::BeginPlot("Line Plot", "x", "f(x)")) {
- ImPlot::PlotLine("sin(x)", xs1, ys1, 1001);
- ImPlot::SetNextMarkerStyle(ImPlotMarker_Circle);
- ImPlot::PlotLine("x^2", xs2, ys2, 11);
- ImPlot::EndPlot();
+ static bool show_lines = true;
+ static bool show_fills = true;
+ static float fill_ref = 0;
+ static int shade_mode = 0;
+ ImGui::Checkbox("Lines",&show_lines); ImGui::SameLine();
+ ImGui::Checkbox("Fills",&show_fills);
+ if (show_fills) {
+ ImGui::SameLine();
+ if (ImGui::RadioButton("To -INF",shade_mode == 0))
+ shade_mode = 0;
+ ImGui::SameLine();
+ if (ImGui::RadioButton("To +INF",shade_mode == 1))
+ shade_mode = 1;
+ ImGui::SameLine();
+ if (ImGui::RadioButton("To Ref",shade_mode == 2))
+ shade_mode = 2;
+ if (shade_mode == 2) {
+ ImGui::SameLine();
+ ImGui::SetNextItemWidth(100);
+ ImGui::DragFloat("##Ref",&fill_ref, 1, -100, 500);
}
}
- //-------------------------------------------------------------------------
- if (ImGui::CollapsingHeader("Filled Line Plots")) {
- static double xs1[101], ys1[101], ys2[101], ys3[101];
- srand(0);
- for (int i = 0; i < 101; ++i) {
- xs1[i] = (float)i;
- ys1[i] = RandomRange(400.0,450.0);
- ys2[i] = RandomRange(275.0,350.0);
- ys3[i] = RandomRange(150.0,225.0);
- }
- static bool show_lines = true;
- static bool show_fills = true;
- static float fill_ref = 0;
- static int shade_mode = 0;
- ImGui::Checkbox("Lines",&show_lines); ImGui::SameLine();
- ImGui::Checkbox("Fills",&show_fills);
+
+ if (ImPlot::BeginPlot("Stock Prices")) {
+ ImPlot::SetupAxes("Days","Price");
+ ImPlot::SetupAxesLimits(0,100,0,500);
if (show_fills) {
- ImGui::SameLine();
- if (ImGui::RadioButton("To -INF",shade_mode == 0))
- shade_mode = 0;
- ImGui::SameLine();
- if (ImGui::RadioButton("To +INF",shade_mode == 1))
- shade_mode = 1;
- ImGui::SameLine();
- if (ImGui::RadioButton("To Ref",shade_mode == 2))
- shade_mode = 2;
- if (shade_mode == 2) {
- ImGui::SameLine();
- ImGui::SetNextItemWidth(100);
- ImGui::DragFloat("##Ref",&fill_ref, 1, -100, 500);
- }
+ ImPlot::PushStyleVar(ImPlotStyleVar_FillAlpha, 0.25f);
+ ImPlot::PlotShaded("Stock 1", xs1, ys1, 101, shade_mode == 0 ? -INFINITY : shade_mode == 1 ? INFINITY : fill_ref);
+ ImPlot::PlotShaded("Stock 2", xs1, ys2, 101, shade_mode == 0 ? -INFINITY : shade_mode == 1 ? INFINITY : fill_ref);
+ ImPlot::PlotShaded("Stock 3", xs1, ys3, 101, shade_mode == 0 ? -INFINITY : shade_mode == 1 ? INFINITY : fill_ref);
+ ImPlot::PopStyleVar();
}
+ if (show_lines) {
+ ImPlot::PlotLine("Stock 1", xs1, ys1, 101);
+ ImPlot::PlotLine("Stock 2", xs1, ys2, 101);
+ ImPlot::PlotLine("Stock 3", xs1, ys3, 101);
+ }
+ ImPlot::EndPlot();
+ }
+}
+//-----------------------------------------------------------------------------
- ImPlot::SetNextPlotLimits(0,100,0,500);
- if (ImPlot::BeginPlot("Stock Prices", "Days", "Price")) {
- if (show_fills) {
- ImPlot::PushStyleVar(ImPlotStyleVar_FillAlpha, 0.25f);
- ImPlot::PlotShaded("Stock 1", xs1, ys1, 101, shade_mode == 0 ? -INFINITY : shade_mode == 1 ? INFINITY : fill_ref);
- ImPlot::PlotShaded("Stock 2", xs1, ys2, 101, shade_mode == 0 ? -INFINITY : shade_mode == 1 ? INFINITY : fill_ref);
- ImPlot::PlotShaded("Stock 3", xs1, ys3, 101, shade_mode == 0 ? -INFINITY : shade_mode == 1 ? INFINITY : fill_ref);
- ImPlot::PopStyleVar();
- }
- if (show_lines) {
- ImPlot::PlotLine("Stock 1", xs1, ys1, 101);
- ImPlot::PlotLine("Stock 2", xs1, ys2, 101);
- ImPlot::PlotLine("Stock 3", xs1, ys3, 101);
- }
- ImPlot::EndPlot();
- }
+void ShowDemo_ShadedPlots() {
+ static float xs[1001], ys[1001], ys1[1001], ys2[1001], ys3[1001], ys4[1001];
+ srand(0);
+ for (int i = 0; i < 1001; ++i) {
+ xs[i] = i * 0.001f;
+ ys[i] = 0.25f + 0.25f * sinf(25 * xs[i]) * sinf(5 * xs[i]) + RandomRange(-0.01f, 0.01f);
+ ys1[i] = ys[i] + RandomRange(0.1f, 0.12f);
+ ys2[i] = ys[i] - RandomRange(0.1f, 0.12f);
+ ys3[i] = 0.75f + 0.2f * sinf(25 * xs[i]);
+ ys4[i] = 0.75f + 0.1f * cosf(25 * xs[i]);
}
- //-------------------------------------------------------------------------
- if (ImGui::CollapsingHeader("Shaded Plots##")) {
- static float xs[1001], ys[1001], ys1[1001], ys2[1001], ys3[1001], ys4[1001];
- srand(0);
- for (int i = 0; i < 1001; ++i) {
- xs[i] = i * 0.001f;
- ys[i] = 0.25f + 0.25f * sinf(25 * xs[i]) * sinf(5 * xs[i]) + RandomRange(-0.01f, 0.01f);
- ys1[i] = ys[i] + RandomRange(0.1f, 0.12f);
- ys2[i] = ys[i] - RandomRange(0.1f, 0.12f);
- ys3[i] = 0.75f + 0.2f * sinf(25 * xs[i]);
- ys4[i] = 0.75f + 0.1f * cosf(25 * xs[i]);
- }
- static float alpha = 0.25f;
- ImGui::DragFloat("Alpha",&alpha,0.01f,0,1);
+ static float alpha = 0.25f;
+ ImGui::DragFloat("Alpha",&alpha,0.01f,0,1);
- if (ImPlot::BeginPlot("Shaded Plots", "X-Axis", "Y-Axis")) {
- ImPlot::PushStyleVar(ImPlotStyleVar_FillAlpha, alpha);
- ImPlot::PlotShaded("Uncertain Data",xs,ys1,ys2,1001);
- ImPlot::PlotLine("Uncertain Data", xs, ys, 1001);
- ImPlot::PlotShaded("Overlapping",xs,ys3,ys4,1001);
- ImPlot::PlotLine("Overlapping",xs,ys3,1001);
- ImPlot::PlotLine("Overlapping",xs,ys4,1001);
- ImPlot::PopStyleVar();
- ImPlot::EndPlot();
- }
+ if (ImPlot::BeginPlot("Shaded Plots")) {
+ ImPlot::PushStyleVar(ImPlotStyleVar_FillAlpha, alpha);
+ ImPlot::PlotShaded("Uncertain Data",xs,ys1,ys2,1001);
+ ImPlot::PlotLine("Uncertain Data", xs, ys, 1001);
+ ImPlot::PlotShaded("Overlapping",xs,ys3,ys4,1001);
+ ImPlot::PlotLine("Overlapping",xs,ys3,1001);
+ ImPlot::PlotLine("Overlapping",xs,ys4,1001);
+ ImPlot::PopStyleVar();
+ ImPlot::EndPlot();
}
- //-------------------------------------------------------------------------
- if (ImGui::CollapsingHeader("Scatter Plots")) {
- srand(0);
- static float xs1[100], ys1[100];
- for (int i = 0; i < 100; ++i) {
- xs1[i] = i * 0.01f;
- ys1[i] = xs1[i] + 0.1f * ((float)rand() / (float)RAND_MAX);
- }
- static float xs2[50], ys2[50];
- for (int i = 0; i < 50; i++) {
- xs2[i] = 0.25f + 0.2f * ((float)rand() / (float)RAND_MAX);
- ys2[i] = 0.75f + 0.2f * ((float)rand() / (float)RAND_MAX);
- }
+}
- if (ImPlot::BeginPlot("Scatter Plot", NULL, NULL)) {
- ImPlot::PlotScatter("Data 1", xs1, ys1, 100);
- ImPlot::PushStyleVar(ImPlotStyleVar_FillAlpha, 0.25f);
- ImPlot::SetNextMarkerStyle(ImPlotMarker_Square, 6, ImVec4(0,1,0,0.5f), IMPLOT_AUTO, ImVec4(0,1,0,1));
- ImPlot::PlotScatter("Data 2", xs2, ys2, 50);
- ImPlot::PopStyleVar();
- ImPlot::EndPlot();
- }
+//-----------------------------------------------------------------------------
+
+void ShowDemo_ScatterPlots() {
+ srand(0);
+ static float xs1[100], ys1[100];
+ for (int i = 0; i < 100; ++i) {
+ xs1[i] = i * 0.01f;
+ ys1[i] = xs1[i] + 0.1f * ((float)rand() / (float)RAND_MAX);
}
- //-------------------------------------------------------------------------
- if (ImGui::CollapsingHeader("Stairstep Plots")) {
- static float ys1[101], ys2[101];
- for (int i = 0; i < 101; ++i) {
- ys1[i] = 0.5f + 0.4f * sinf(50 * i * 0.01f);
- ys2[i] = 0.5f + 0.2f * sinf(25 * i * 0.01f);
- }
- if (ImPlot::BeginPlot("Stairstep Plot", "x", "f(x)")) {
- ImPlot::PlotStairs("Signal 1", ys1, 101, 0.01f);
- ImPlot::SetNextMarkerStyle(ImPlotMarker_Square, 2.0f);
- ImPlot::PlotStairs("Signal 2", ys2, 101, 0.01f);
- ImPlot::EndPlot();
- }
+ static float xs2[50], ys2[50];
+ for (int i = 0; i < 50; i++) {
+ xs2[i] = 0.25f + 0.2f * ((float)rand() / (float)RAND_MAX);
+ ys2[i] = 0.75f + 0.2f * ((float)rand() / (float)RAND_MAX);
}
- //-------------------------------------------------------------------------
- if (ImGui::CollapsingHeader("Bar Plots")) {
- static bool horz = false;
- static ImS8 midtm[10] = {83, 67, 23, 89, 83, 78, 91, 82, 85, 90};
- static ImS16 final[10] = {80, 62, 56, 99, 55, 78, 88, 78, 90, 100};
- static ImS32 grade[10] = {80, 69, 52, 92, 72, 78, 75, 76, 89, 95};
+ if (ImPlot::BeginPlot("Scatter Plot")) {
+ ImPlot::PlotScatter("Data 1", xs1, ys1, 100);
+ ImPlot::PushStyleVar(ImPlotStyleVar_FillAlpha, 0.25f);
+ ImPlot::SetNextMarkerStyle(ImPlotMarker_Square, 6, ImPlot::GetColormapColor(1), IMPLOT_AUTO, ImPlot::GetColormapColor(1));
+ ImPlot::PlotScatter("Data 2", xs2, ys2, 50);
+ ImPlot::PopStyleVar();
+ ImPlot::EndPlot();
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+void ShowDemo_StairstepPlots() {
+ static float ys1[101], ys2[101];
+ for (int i = 0; i < 101; ++i) {
+ ys1[i] = 0.5f + 0.4f * sinf(50 * i * 0.01f);
+ ys2[i] = 0.5f + 0.2f * sinf(25 * i * 0.01f);
+ }
+ if (ImPlot::BeginPlot("Stairstep Plot")) {
+ ImPlot::SetupAxes("x","f(x)");
+ ImPlot::PlotStairs("Signal 1", ys1, 101, 0.01f);
+ ImPlot::SetNextMarkerStyle(ImPlotMarker_Square, 2.0f);
+ ImPlot::PlotStairs("Signal 2", ys2, 101, 0.01f);
+ ImPlot::EndPlot();
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+void ShowDemo_BarPlots() {
+ static ImS8 data[10] = {1,2,3,4,5,6,7,8,9,10};
+ if (ImPlot::BeginPlot("Bar Plot")) {
+ ImPlot::PlotBars("Bars",data,10,0.7,1);
+ ImPlot::PlotBarsH("BarsH",data,10,0.4,1);
+ ImPlot::EndPlot();
+ }
+}
+
+void ShowDemo_BarGroups() {
+ static ImS8 data[30] = {83, 67, 23, 89, 83, 78, 91, 82, 85, 90, // midterm
+ 80, 62, 56, 99, 55, 78, 88, 78, 90, 100, // final
+ 80, 69, 52, 92, 72, 78, 75, 76, 89, 95}; // course
+
+ static const char* ilabels[] = {"Midterm Exam","Final Exam","Course Grade"};
+ static const char* glabels[] = {"S1","S2","S3","S4","S5","S6","S7","S8","S9","S10"};
+ static const double positions[] = {0,1,2,3,4,5,6,7,8,9};
- static const char* labels[] = {"S1","S2","S3","S4","S5","S6","S7","S8","S9","S10"};
- static const double positions[] = {0,1,2,3,4,5,6,7,8,9};
+ static int items = 3;
+ static int groups = 10;
+ static float size = 0.67f;
- ImGui::Checkbox("Horizontal",&horz);
+ static ImPlotBarGroupsFlags flags = 0;
+ static bool horz = false;
+ ImGui::CheckboxFlags("Stacked", (unsigned int*)&flags, ImPlotBarGroupsFlags_Stacked);
+ ImGui::SameLine();
+ ImGui::Checkbox("Horizontal",&horz);
+
+ ImGui::SliderInt("Items",&items,1,3);
+ ImGui::SliderFloat("Size",&size,0,1);
+
+ if (ImPlot::BeginPlot("Bar Group")) {
+ ImPlot::SetupLegend(ImPlotLocation_East, ImPlotLegendFlags_Outside);
if (horz) {
- ImPlot::SetNextPlotLimits(0, 110, -0.5, 9.5, ImGuiCond_Always);
- ImPlot::SetNextPlotTicksY(positions, 10, labels);
+ ImPlot::SetupAxes("Score","Student",ImPlotAxisFlags_AutoFit,ImPlotAxisFlags_AutoFit);
+ ImPlot::SetupAxisTicks(ImAxis_Y1,positions, groups, glabels);
+ ImPlot::PlotBarGroupsH(ilabels,data,items,groups,size,0,flags);
}
else {
- ImPlot::SetNextPlotLimits(-0.5, 9.5, 0, 110, ImGuiCond_Always);
- ImPlot::SetNextPlotTicksX(positions, 10, labels);
- }
- if (ImPlot::BeginPlot("Bar Plot", horz ? "Score" : "Student", horz ? "Student" : "Score",
- ImVec2(-1,0), 0, 0, horz ? ImPlotAxisFlags_Invert : 0))
- {
- if (horz) {
- ImPlot::SetLegendLocation(ImPlotLocation_West, ImPlotOrientation_Vertical);
- ImPlot::PlotBarsH("Midterm Exam", midtm, 10, 0.2, -0.2);
- ImPlot::PlotBarsH("Final Exam", final, 10, 0.2, 0);
- ImPlot::PlotBarsH("Course Grade", grade, 10, 0.2, 0.2);
- }
- else {
- ImPlot::SetLegendLocation(ImPlotLocation_South, ImPlotOrientation_Horizontal);
- ImPlot::PlotBars("Midterm Exam", midtm, 10, 0.2, -0.2);
- ImPlot::PlotBars("Final Exam", final, 10, 0.2, 0);
- ImPlot::PlotBars("Course Grade", grade, 10, 0.2, 0.2);
- }
- ImPlot::EndPlot();
+ ImPlot::SetupAxes("Student","Score",ImPlotAxisFlags_AutoFit,ImPlotAxisFlags_AutoFit);
+ ImPlot::SetupAxisTicks(ImAxis_X1,positions, groups, glabels);
+ ImPlot::PlotBarGroups(ilabels,data,items,groups,size,0,flags);
}
+ ImPlot::EndPlot();
}
- //-------------------------------------------------------------------------
- if (ImGui::CollapsingHeader("Error Bars")) {
- static float xs[5] = {1,2,3,4,5};
- static float bar[5] = {1,2,5,3,4};
- static float lin1[5] = {8,8,9,7,8};
- static float lin2[5] = {6,7,6,9,6};
- static float err1[5] = {0.2f, 0.4f, 0.2f, 0.6f, 0.4f};
- static float err2[5] = {0.4f, 0.2f, 0.4f, 0.8f, 0.6f};
- static float err3[5] = {0.09f, 0.14f, 0.09f, 0.12f, 0.16f};
- static float err4[5] = {0.02f, 0.08f, 0.15f, 0.05f, 0.2f};
+}
+void ShowDemo_BarStacks() {
- ImPlot::SetNextPlotLimits(0, 6, 0, 10);
- if (ImPlot::BeginPlot("##ErrorBars",NULL,NULL)) {
+ static ImPlotColormap Liars = -1;
+ if (Liars == -1) {
+ static const ImU32 Liars_Data[6] = { 4282515870, 4282609140, 4287357182, 4294630301, 4294945280, 4294921472 };
+ Liars = ImPlot::AddColormap("Liars", Liars_Data, 6);
+ }
- ImPlot::PlotBars("Bar", xs, bar, 5, 0.5f);
- ImPlot::PlotErrorBars("Bar", xs, bar, err1, 5);
+ static bool diverging = true;
+ ImGui::Checkbox("Diverging",&diverging);
- ImPlot::SetNextErrorBarStyle(ImPlot::GetColormapColor(1), 0);
- ImPlot::PlotErrorBars("Line", xs, lin1, err1, err2, 5);
- ImPlot::SetNextMarkerStyle(ImPlotMarker_Circle);
- ImPlot::PlotLine("Line", xs, lin1, 5);
+ static const char* politicians[] = {"Trump","Bachman","Cruz","Gingrich","Palin","Santorum","Walker","Perry","Ryan","McCain","Rubio","Romney","Rand Paul","Christie","Biden","Kasich","Sanders","J Bush","H Clinton","Obama"};
+ static int data_reg[] = {18,26,7,14,10,8,6,11,4,4,3,8,6,8,6,5,0,3,1,2, // Pants on Fire
+ 43,36,30,21,30,27,25,17,11,22,15,16,16,17,12,12,14,6,13,12, // False
+ 16,13,28,22,15,21,15,18,30,17,24,18,13,10,14,15,17,22,14,12, // Mostly False
+ 17,10,13,25,12,22,19,26,23,17,22,27,20,26,29,17,18,22,21,27, // Half True
+ 5,7,16,10,10,12,23,13,17,20,22,16,23,19,20,26,36,29,27,26, // Mostly True
+ 1,8,6,8,23,10,12,15,15,20,14,15,22,20,19,25,15,18,24,21}; // True
+ static const char* labels_reg[] = {"Pants on Fire","False","Mostly False","Half True","Mostly True","True"};
- ImPlot::PushStyleColor(ImPlotCol_ErrorBar, ImPlot::GetColormapColor(2));
- ImPlot::PlotErrorBars("Scatter", xs, lin2, err2, 5);
- ImPlot::PlotErrorBarsH("Scatter", xs, lin2, err3, err4, 5);
- ImPlot::PopStyleColor();
- ImPlot::PlotScatter("Scatter", xs, lin2, 5);
- ImPlot::EndPlot();
- }
+ static int data_div[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // Pants on Fire (dummy, to order legend logically)
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // False (dummy, to order legend logically)
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // Mostly False (dummy, to order legend logically)
+ -16,-13,-28,-22,-15,-21,-15,-18,-30,-17,-24,-18,-13,-10,-14,-15,-17,-22,-14,-12, // Mostly False
+ -43,-36,-30,-21,-30,-27,-25,-17,-11,-22,-15,-16,-16,-17,-12,-12,-14,-6,-13,-12, // False
+ -18,-26,-7,-14,-10,-8,-6,-11,-4,-4,-3,-8,-6,-8,-6,-5,0,-3,-1,-2, // Pants on Fire
+ 17,10,13,25,12,22,19,26,23,17,22,27,20,26,29,17,18,22,21,27, // Half True
+ 5,7,16,10,10,12,23,13,17,20,22,16,23,19,20,26,36,29,27,26, // Mostly True
+ 1,8,6,8,23,10,12,15,15,20,14,15,22,20,19,25,15,18,24,21}; // True
+ static const char* labels_div[] = {"Pants on Fire","False","Mostly False","Mostly False","False","Pants on Fire","Half True","Mostly True","True"};
+
+ ImPlot::PushColormap(Liars);
+ if (ImPlot::BeginPlot("PolitiFact: Who Lies More?",ImVec2(-1,400),ImPlotFlags_NoMouseText)) {
+ ImPlot::SetupLegend(ImPlotLocation_South, ImPlotLegendFlags_Outside|ImPlotLegendFlags_Horizontal);
+ ImPlot::SetupAxes(NULL,NULL,ImPlotAxisFlags_AutoFit|ImPlotAxisFlags_NoDecorations,ImPlotAxisFlags_AutoFit|ImPlotAxisFlags_Invert);
+ ImPlot::SetupAxisTicks(ImAxis_Y1,0,19,20,politicians,false);
+ if (diverging)
+ ImPlot::PlotBarGroupsH(labels_div,data_div,9,20,0.75,0,ImPlotBarGroupsFlags_Stacked);
+ else
+ ImPlot::PlotBarGroupsH(labels_reg,data_reg,6,20,0.75,0,ImPlotBarGroupsFlags_Stacked);
+ ImPlot::EndPlot();
}
- //-------------------------------------------------------------------------
- if (ImGui::CollapsingHeader("Stem Plots##")) {
- static double xs[51], ys1[51], ys2[51];
- for (int i = 0; i < 51; ++i) {
- xs[i] = i * 0.02;
- ys1[i] = 1.0 + 0.5 * sin(25*xs[i])*cos(2*xs[i]);
- ys2[i] = 0.5 + 0.25 * sin(10*xs[i]) * sin(xs[i]);
- }
- ImPlot::SetNextPlotLimits(0,1,0,1.6);
- if (ImPlot::BeginPlot("Stem Plots")) {
- ImPlot::PlotStems("Stems 1",xs,ys1,51);
- ImPlot::SetNextLineStyle(ImVec4(1,0.5f,0,0.75f));
- ImPlot::SetNextMarkerStyle(ImPlotMarker_Square,5,ImVec4(1,0.5f,0,0.25f));
- ImPlot::PlotStems("Stems 2", xs, ys2,51);
- ImPlot::EndPlot();
- }
+ ImPlot::PopColormap();
+}
+
+//-----------------------------------------------------------------------------
+
+void ShowDemo_ErrorBars() {
+ static float xs[5] = {1,2,3,4,5};
+ static float bar[5] = {1,2,5,3,4};
+ static float lin1[5] = {8,8,9,7,8};
+ static float lin2[5] = {6,7,6,9,6};
+ static float err1[5] = {0.2f, 0.4f, 0.2f, 0.6f, 0.4f};
+ static float err2[5] = {0.4f, 0.2f, 0.4f, 0.8f, 0.6f};
+ static float err3[5] = {0.09f, 0.14f, 0.09f, 0.12f, 0.16f};
+ static float err4[5] = {0.02f, 0.08f, 0.15f, 0.05f, 0.2f};
+
+
+ if (ImPlot::BeginPlot("##ErrorBars")) {
+ ImPlot::SetupAxesLimits(0, 6, 0, 10);
+ ImPlot::PlotBars("Bar", xs, bar, 5, 0.5f);
+ ImPlot::PlotErrorBars("Bar", xs, bar, err1, 5);
+ ImPlot::SetNextErrorBarStyle(ImPlot::GetColormapColor(1), 0);
+ ImPlot::PlotErrorBars("Line", xs, lin1, err1, err2, 5);
+ ImPlot::SetNextMarkerStyle(ImPlotMarker_Circle);
+ ImPlot::PlotLine("Line", xs, lin1, 5);
+ ImPlot::PushStyleColor(ImPlotCol_ErrorBar, ImPlot::GetColormapColor(2));
+ ImPlot::PlotErrorBars("Scatter", xs, lin2, err2, 5);
+ ImPlot::PlotErrorBarsH("Scatter", xs, lin2, err3, err4, 5);
+ ImPlot::PopStyleColor();
+ ImPlot::PlotScatter("Scatter", xs, lin2, 5);
+ ImPlot::EndPlot();
}
- //-------------------------------------------------------------------------
- if (ImGui::CollapsingHeader("Infinite Lines")) {
- static double vals[] = {0.25, 0.5, 0.75};
- if (ImPlot::BeginPlot("##Infinite",0,0,ImVec2(-1,0),0,ImPlotAxisFlags_NoInitialFit,ImPlotAxisFlags_NoInitialFit)) {
- ImPlot::PlotVLines("VLines",vals,3);
- ImPlot::PlotHLines("HLines",vals,3);
- ImPlot::EndPlot();
- }
+}
+
+void ShowDemo_StemPlots() {
+ static double xs[51], ys1[51], ys2[51];
+ for (int i = 0; i < 51; ++i) {
+ xs[i] = i * 0.02;
+ ys1[i] = 1.0 + 0.5 * sin(25*xs[i])*cos(2*xs[i]);
+ ys2[i] = 0.5 + 0.25 * sin(10*xs[i]) * sin(xs[i]);
}
- //-------------------------------------------------------------------------
- if (ImGui::CollapsingHeader("Pie Charts")) {
- static const char* labels1[] = {"Frogs","Hogs","Dogs","Logs"};
- static float data1[] = {0.15f, 0.30f, 0.2f, 0.05f};
- static bool normalize = false;
- ImGui::SetNextItemWidth(250);
- ImGui::DragFloat4("Values", data1, 0.01f, 0, 1);
- if ((data1[0] + data1[1] + data1[2] + data1[3]) < 1) {
- ImGui::SameLine();
- ImGui::Checkbox("Normalize", &normalize);
- }
+ if (ImPlot::BeginPlot("Stem Plots")) {
+ ImPlot::SetupAxisLimits(ImAxis_X1,0,1.0);
+ ImPlot::SetupAxisLimits(ImAxis_Y1,0,1.6);
+ ImPlot::PlotStems("Stems 1",xs,ys1,51);
+ ImPlot::SetNextMarkerStyle(ImPlotMarker_Square,5);
+ ImPlot::PlotStems("Stems 2", xs, ys2,51);
+ ImPlot::EndPlot();
+ }
+}
- ImPlot::SetNextPlotLimits(0,1,0,1,ImGuiCond_Always);
- if (ImPlot::BeginPlot("##Pie1", NULL, NULL, ImVec2(250,250), ImPlotFlags_Equal | ImPlotFlags_NoMousePos, ImPlotAxisFlags_NoDecorations, ImPlotAxisFlags_NoDecorations)) {
- ImPlot::PlotPieChart(labels1, data1, 4, 0.5, 0.5, 0.4, normalize, "%.2f");
- ImPlot::EndPlot();
- }
+void ShowDemo_InfiniteLines() {
+ static double vals[] = {0.25, 0.5, 0.75};
+ if (ImPlot::BeginPlot("##Infinite")) {
+ ImPlot::SetupAxes(NULL,NULL,ImPlotAxisFlags_NoInitialFit,ImPlotAxisFlags_NoInitialFit);
+ ImPlot::PlotVLines("VLines",vals,3);
+ ImPlot::PlotHLines("HLines",vals,3);
+ ImPlot::EndPlot();
+ }
+}
+void ShowDemo_PieCharts() {
+ static const char* labels1[] = {"Frogs","Hogs","Dogs","Logs"};
+ static float data1[] = {0.15f, 0.30f, 0.2f, 0.05f};
+ static bool normalize = false;
+ ImGui::SetNextItemWidth(250);
+ ImGui::DragFloat4("Values", data1, 0.01f, 0, 1);
+ if ((data1[0] + data1[1] + data1[2] + data1[3]) < 1) {
ImGui::SameLine();
+ ImGui::Checkbox("Normalize", &normalize);
+ }
- static const char* labels2[] = {"A","B","C","D","E"};
- static int data2[] = {1,1,2,3,5};
+ if (ImPlot::BeginPlot("##Pie1", ImVec2(250,250), ImPlotFlags_Equal | ImPlotFlags_NoMouseText)) {
+ ImPlot::SetupAxes(NULL, NULL, ImPlotAxisFlags_NoDecorations, ImPlotAxisFlags_NoDecorations);
+ ImPlot::SetupAxesLimits(0, 1, 0, 1);
+ ImPlot::PlotPieChart(labels1, data1, 4, 0.5, 0.5, 0.4, normalize, "%.2f");
+ ImPlot::EndPlot();
+ }
- ImPlot::PushColormap(ImPlotColormap_Pastel);
- ImPlot::SetNextPlotLimits(0,1,0,1,ImGuiCond_Always);
- if (ImPlot::BeginPlot("##Pie2", NULL, NULL, ImVec2(250,250), ImPlotFlags_Equal | ImPlotFlags_NoMousePos, ImPlotAxisFlags_NoDecorations, ImPlotAxisFlags_NoDecorations)) {
- ImPlot::PlotPieChart(labels2, data2, 5, 0.5, 0.5, 0.4, true, "%.0f", 180);
- ImPlot::EndPlot();
- }
- ImPlot::PopColormap();
+ ImGui::SameLine();
+
+ static const char* labels2[] = {"A","B","C","D","E"};
+ static int data2[] = {1,1,2,3,5};
+
+ ImPlot::PushColormap(ImPlotColormap_Pastel);
+ if (ImPlot::BeginPlot("##Pie2", ImVec2(250,250), ImPlotFlags_Equal | ImPlotFlags_NoMouseText)) {
+ ImPlot::SetupAxes(NULL, NULL, ImPlotAxisFlags_NoDecorations, ImPlotAxisFlags_NoDecorations);
+ ImPlot::SetupAxesLimits(0, 1, 0, 1);
+ ImPlot::PlotPieChart(labels2, data2, 5, 0.5, 0.5, 0.4, true, "%.0f", 180);
+ ImPlot::EndPlot();
}
- //-------------------------------------------------------------------------
- if (ImGui::CollapsingHeader("Heatmaps")) {
- static float values1[7][7] = {{0.8f, 2.4f, 2.5f, 3.9f, 0.0f, 4.0f, 0.0f},
- {2.4f, 0.0f, 4.0f, 1.0f, 2.7f, 0.0f, 0.0f},
- {1.1f, 2.4f, 0.8f, 4.3f, 1.9f, 4.4f, 0.0f},
- {0.6f, 0.0f, 0.3f, 0.0f, 3.1f, 0.0f, 0.0f},
- {0.7f, 1.7f, 0.6f, 2.6f, 2.2f, 6.2f, 0.0f},
- {1.3f, 1.2f, 0.0f, 0.0f, 0.0f, 3.2f, 5.1f},
- {0.1f, 2.0f, 0.0f, 1.4f, 0.0f, 1.9f, 6.3f}};
- static float scale_min = 0;
- static float scale_max = 6.3f;
- static const char* xlabels[] = {"C1","C2","C3","C4","C5","C6","C7"};
- static const char* ylabels[] = {"R1","R2","R3","R4","R5","R6","R7"};
+ ImPlot::PopColormap();
+}
- static ImPlotColormap map = ImPlotColormap_Viridis;
- if (ImPlot::ColormapButton(ImPlot::GetColormapName(map),ImVec2(225,0),map)) {
- map = (map + 1) % ImPlot::GetColormapCount();
- // We bust the color cache of our plots so that item colors will
- // resample the new colormap in the event that they have already
- // been created. See documentation in implot.h.
- BustColorCache("##Heatmap1");
- BustColorCache("##Heatmap2");
- }
+void ShowDemo_Heatmaps() {
+ static float values1[7][7] = {{0.8f, 2.4f, 2.5f, 3.9f, 0.0f, 4.0f, 0.0f},
+ {2.4f, 0.0f, 4.0f, 1.0f, 2.7f, 0.0f, 0.0f},
+ {1.1f, 2.4f, 0.8f, 4.3f, 1.9f, 4.4f, 0.0f},
+ {0.6f, 0.0f, 0.3f, 0.0f, 3.1f, 0.0f, 0.0f},
+ {0.7f, 1.7f, 0.6f, 2.6f, 2.2f, 6.2f, 0.0f},
+ {1.3f, 1.2f, 0.0f, 0.0f, 0.0f, 3.2f, 5.1f},
+ {0.1f, 2.0f, 0.0f, 1.4f, 0.0f, 1.9f, 6.3f}};
+ static float scale_min = 0;
+ static float scale_max = 6.3f;
+ static const char* xlabels[] = {"C1","C2","C3","C4","C5","C6","C7"};
+ static const char* ylabels[] = {"R1","R2","R3","R4","R5","R6","R7"};
- ImGui::SameLine();
- ImGui::LabelText("##Colormap Index", "%s", "Change Colormap");
- ImGui::SetNextItemWidth(225);
- ImGui::DragFloatRange2("Min / Max",&scale_min, &scale_max, 0.01f, -20, 20);
- static ImPlotAxisFlags axes_flags = ImPlotAxisFlags_Lock | ImPlotAxisFlags_NoGridLines | ImPlotAxisFlags_NoTickMarks;
+ static ImPlotColormap map = ImPlotColormap_Viridis;
+ if (ImPlot::ColormapButton(ImPlot::GetColormapName(map),ImVec2(225,0),map)) {
+ map = (map + 1) % ImPlot::GetColormapCount();
+ // We bust the color cache of our plots so that item colors will
+ // resample the new colormap in the event that they have already
+ // been created. See documentation in implot.h.
+ BustColorCache("##Heatmap1");
+ BustColorCache("##Heatmap2");
+ }
- ImPlot::PushColormap(map);
- SetNextPlotTicksX(0 + 1.0/14.0, 1 - 1.0/14.0, 7, xlabels);
- SetNextPlotTicksY(1 - 1.0/14.0, 0 + 1.0/14.0, 7, ylabels);
- if (ImPlot::BeginPlot("##Heatmap1",NULL,NULL,ImVec2(225,225),ImPlotFlags_NoLegend|ImPlotFlags_NoMousePos,axes_flags,axes_flags)) {
- ImPlot::PlotHeatmap("heat",values1[0],7,7,scale_min,scale_max);
- ImPlot::EndPlot();
- }
- ImGui::SameLine();
- ImPlot::ColormapScale("##HeatScale",scale_min, scale_max, ImVec2(60,225));
+ ImGui::SameLine();
+ ImGui::LabelText("##Colormap Index", "%s", "Change Colormap");
+ ImGui::SetNextItemWidth(225);
+ ImGui::DragFloatRange2("Min / Max",&scale_min, &scale_max, 0.01f, -20, 20);
+ static ImPlotAxisFlags axes_flags = ImPlotAxisFlags_Lock | ImPlotAxisFlags_NoGridLines | ImPlotAxisFlags_NoTickMarks;
- ImGui::SameLine();
+ ImPlot::PushColormap(map);
+
+ if (ImPlot::BeginPlot("##Heatmap1",ImVec2(225,225),ImPlotFlags_NoLegend|ImPlotFlags_NoMouseText)) {
+ ImPlot::SetupAxes(NULL, NULL, axes_flags, axes_flags);
+ ImPlot::SetupAxisTicks(ImAxis_X1,0 + 1.0/14.0, 1 - 1.0/14.0, 7, xlabels);
+ ImPlot::SetupAxisTicks(ImAxis_Y1,1 - 1.0/14.0, 0 + 1.0/14.0, 7, ylabels);
+ ImPlot::PlotHeatmap("heat",values1[0],7,7,scale_min,scale_max);
+ ImPlot::EndPlot();
+ }
+ ImGui::SameLine();
+ ImPlot::ColormapScale("##HeatScale",scale_min, scale_max, ImVec2(60,225));
- const int size = 200;
- static double values2[size*size];
- srand((unsigned int)(DEMO_TIME*1000000));
- for (int i = 0; i < size*size; ++i)
- values2[i] = RandomRange(0.0,1.0);
+ ImGui::SameLine();
- ImPlot::SetNextPlotLimits(-1,1,-1,1);
- if (ImPlot::BeginPlot("##Heatmap2",NULL,NULL,ImVec2(225,225),0,ImPlotAxisFlags_NoDecorations,ImPlotAxisFlags_NoDecorations)) {
- ImPlot::PlotHeatmap("heat1",values2,size,size,0,1,NULL);
- ImPlot::PlotHeatmap("heat2",values2,size,size,0,1,NULL, ImPlotPoint(-1,-1), ImPlotPoint(0,0));
- ImPlot::EndPlot();
- }
- ImPlot::PopColormap();
+ const int size = 200;
+ static double values2[size*size];
+ srand((unsigned int)(ImGui::GetTime()*1000000));
+ for (int i = 0; i < size*size; ++i)
+ values2[i] = RandomRange(0.0,1.0);
+ if (ImPlot::BeginPlot("##Heatmap2",ImVec2(225,225))) {
+ ImPlot::SetupAxes(NULL, NULL, ImPlotAxisFlags_NoDecorations, ImPlotAxisFlags_NoDecorations);
+ ImPlot::SetupAxesLimits(-1,1,-1,1);
+ ImPlot::PlotHeatmap("heat1",values2,size,size,0,1,NULL);
+ ImPlot::PlotHeatmap("heat2",values2,size,size,0,1,NULL, ImPlotPoint(-1,-1), ImPlotPoint(0,0));
+ ImPlot::EndPlot();
}
- //-------------------------------------------------------------------------
- if (ImGui::CollapsingHeader("Histograms")) {
- static int bins = 50;
- static bool cumulative = false;
- static bool density = true;
- static bool outliers = true;
- static double mu = 5;
- static double sigma = 2;
+ ImPlot::PopColormap();
+
+}
+
+void ShowDemo_Histogram() {
+ static int bins = 50;
+ static bool cumulative = false;
+ static bool density = true;
+ static bool outliers = true;
+ static double mu = 5;
+ static double sigma = 2;
+ ImGui::SetNextItemWidth(200);
+ if (ImGui::RadioButton("Sqrt",bins==ImPlotBin_Sqrt)) { bins = ImPlotBin_Sqrt; } ImGui::SameLine();
+ if (ImGui::RadioButton("Sturges",bins==ImPlotBin_Sturges)) { bins = ImPlotBin_Sturges; } ImGui::SameLine();
+ if (ImGui::RadioButton("Rice",bins==ImPlotBin_Rice)) { bins = ImPlotBin_Rice; } ImGui::SameLine();
+ if (ImGui::RadioButton("Scott",bins==ImPlotBin_Scott)) { bins = ImPlotBin_Scott; } ImGui::SameLine();
+ if (ImGui::RadioButton("N Bins",bins>=0)) bins = 50;
+ if (bins>=0) {
+ ImGui::SameLine();
ImGui::SetNextItemWidth(200);
- if (ImGui::RadioButton("Sqrt",bins==ImPlotBin_Sqrt)) { bins = ImPlotBin_Sqrt; } ImGui::SameLine();
- if (ImGui::RadioButton("Sturges",bins==ImPlotBin_Sturges)) { bins = ImPlotBin_Sturges; } ImGui::SameLine();
- if (ImGui::RadioButton("Rice",bins==ImPlotBin_Rice)) { bins = ImPlotBin_Rice; } ImGui::SameLine();
- if (ImGui::RadioButton("Scott",bins==ImPlotBin_Scott)) { bins = ImPlotBin_Scott; } ImGui::SameLine();
- if (ImGui::RadioButton("N Bins",bins>=0)) bins = 50;
- if (bins>=0) {
- ImGui::SameLine();
- ImGui::SetNextItemWidth(200);
- ImGui::SliderInt("##Bins", &bins, 1, 100);
- }
- if (ImGui::Checkbox("Density", &density))
- ImPlot::FitNextPlotAxes();
+ ImGui::SliderInt("##Bins", &bins, 1, 100);
+ }
+ if (ImGui::Checkbox("Density", &density))
+ {
+ ImPlot::SetNextAxisToFit(ImAxis_X1);
+ ImPlot::SetNextAxisToFit(ImAxis_Y1);
+ }
+ ImGui::SameLine();
+ if (ImGui::Checkbox("Cumulative", &cumulative))
+ {
+ ImPlot::SetNextAxisToFit(ImAxis_X1);
+ ImPlot::SetNextAxisToFit(ImAxis_Y1);
+ }
+ ImGui::SameLine();
+ static bool range = false;
+ ImGui::Checkbox("Range", &range);
+ static float rmin = -3;
+ static float rmax = 13;
+ if (range) {
ImGui::SameLine();
- if (ImGui::Checkbox("Cumulative", &cumulative))
- ImPlot::FitNextPlotAxes();
+ ImGui::SetNextItemWidth(200);
+ ImGui::DragFloat2("##Range",&rmin,0.1f,-3,13);
ImGui::SameLine();
- static bool range = false;
- ImGui::Checkbox("Range", &range);
- static float rmin = -3;
- static float rmax = 13;
- if (range) {
- ImGui::SameLine();
- ImGui::SetNextItemWidth(200);
- ImGui::DragFloat2("##Range",&rmin,0.1f,-3,13);
- ImGui::SameLine();
- ImGui::Checkbox("Outliers",&outliers);
- }
+ ImGui::Checkbox("Outliers",&outliers);
+ }
- static NormalDistribution<10000> dist(mu, sigma);
- static double x[100];
- static double y[100];
- if (density) {
- for (int i = 0; i < 100; ++i) {
- x[i] = -3 + 16 * (double)i/99.0;
- y[i] = exp( - (x[i]-mu)*(x[i]-mu) / (2*sigma*sigma)) / (sigma * sqrt(2*3.141592653589793238));
- }
- if (cumulative) {
- for (int i = 1; i < 100; ++i)
- y[i] += y[i-1];
- for (int i = 0; i < 100; ++i)
- y[i] /= y[99];
- }
+ static NormalDistribution<10000> dist(mu, sigma);
+ static double x[100];
+ static double y[100];
+ if (density) {
+ for (int i = 0; i < 100; ++i) {
+ x[i] = -3 + 16 * (double)i/99.0;
+ y[i] = exp( - (x[i]-mu)*(x[i]-mu) / (2*sigma*sigma)) / (sigma * sqrt(2*3.141592653589793238));
}
-
- if (ImPlot::BeginPlot("##Histograms")) {
- ImPlot::SetNextFillStyle(IMPLOT_AUTO_COL, 0.5f);
- ImPlot::PlotHistogram("Empirical", dist.Data, 10000, bins, cumulative, density, range ? ImPlotRange(rmin,rmax) : ImPlotRange(), outliers);
- if (density && outliers)
- ImPlot::PlotLine("Theoretical",x,y,100);
- ImPlot::EndPlot();
+ if (cumulative) {
+ for (int i = 1; i < 100; ++i)
+ y[i] += y[i-1];
+ for (int i = 0; i < 100; ++i)
+ y[i] /= y[99];
}
+ }
- static int count = 500000;
- static int xybins[2] = {200,200};
- static bool density2 = false;
- ImGui::SliderInt("Count",&count,100,500000);
- ImGui::SliderInt2("Bins",xybins,1,500);
- ImGui::SameLine();
- ImGui::Checkbox("Density##2",&density2);
- static NormalDistribution<500000> dist1(1, 2);
- static NormalDistribution<500000> dist2(1, 1);
- double max_count = 0;
- ImPlotAxisFlags flags = ImPlotAxisFlags_AutoFit|ImPlotAxisFlags_Foreground;
- ImPlot::PushColormap("Hot");
- if (ImPlot::BeginPlot("##Hist2D",0,0,ImVec2(ImGui::GetContentRegionAvail().x-100-ImGui::GetStyle().ItemSpacing.x,0),0,flags,flags)) {
- max_count = ImPlot::PlotHistogram2D("Hist2D",dist1.Data,dist2.Data,count,xybins[0],xybins[1],density2,ImPlotLimits(-6,6,-6,6));
- ImPlot::EndPlot();
- }
- ImGui::SameLine();
- ImPlot::ColormapScale(density2 ? "Density" : "Count",0,max_count,ImVec2(100,0));
- ImPlot::PopColormap();
+ if (ImPlot::BeginPlot("##Histograms")) {
+ ImPlot::SetNextFillStyle(IMPLOT_AUTO_COL, 0.5f);
+ ImPlot::PlotHistogram("Empirical", dist.Data, 10000, bins, cumulative, density, range ? ImPlotRange(rmin,rmax) : ImPlotRange(), outliers);
+ if (density && outliers)
+ ImPlot::PlotLine("Theoretical",x,y,100);
+ ImPlot::EndPlot();
}
- //-------------------------------------------------------------------------
- if (ImGui::CollapsingHeader("Digital Plots")) {
- ImGui::BulletText("Digital plots do not respond to Y drag and zoom, so that");
- ImGui::Indent();
- ImGui::Text("you can drag analog plots over the rising/falling digital edge.");
- ImGui::Unindent();
+}
- static bool paused = false;
- static ScrollingBuffer dataDigital[2];
- static ScrollingBuffer dataAnalog[2];
- static bool showDigital[2] = {true, false};
- static bool showAnalog[2] = {true, false};
+void ShowDemo_Histogram2D() {
+ static int count = 500000;
+ static int xybins[2] = {200,200};
+ static bool density2 = false;
+ ImGui::SliderInt("Count",&count,100,500000);
+ ImGui::SliderInt2("Bins",xybins,1,500);
+ ImGui::SameLine();
+ ImGui::Checkbox("Density##2",&density2);
+ static NormalDistribution<500000> dist1(1, 2);
+ static NormalDistribution<500000> dist2(1, 1);
+ double max_count = 0;
+ ImPlotAxisFlags flags = ImPlotAxisFlags_AutoFit|ImPlotAxisFlags_Foreground;
+ ImPlot::PushColormap("Hot");
+ if (ImPlot::BeginPlot("##Hist2D",ImVec2(ImGui::GetContentRegionAvail().x-100-ImGui::GetStyle().ItemSpacing.x,0))) {
+ ImPlot::SetupAxes(NULL, NULL, flags, flags);
+ ImPlot::SetupAxesLimits(-6,6,-6,6);
+ max_count = ImPlot::PlotHistogram2D("Hist2D",dist1.Data,dist2.Data,count,xybins[0],xybins[1],density2,ImPlotRect(-6,6,-6,6));
+ ImPlot::EndPlot();
+ }
+ ImGui::SameLine();
+ ImPlot::ColormapScale(density2 ? "Density" : "Count",0,max_count,ImVec2(100,0));
+ ImPlot::PopColormap();
+}
- char label[32];
- ImGui::Checkbox("digital_0", &showDigital[0]); ImGui::SameLine();
- ImGui::Checkbox("digital_1", &showDigital[1]); ImGui::SameLine();
- ImGui::Checkbox("analog_0", &showAnalog[0]); ImGui::SameLine();
- ImGui::Checkbox("analog_1", &showAnalog[1]);
+void ShowDemo_DigitalPlots() {
+ ImGui::BulletText("Digital plots do not respond to Y drag and zoom, so that");
+ ImGui::Indent();
+ ImGui::Text("you can drag analog plots over the rising/falling digital edge.");
+ ImGui::Unindent();
- static float t = 0;
- if (!paused) {
- t += ImGui::GetIO().DeltaTime;
- //digital signal values
- if (showDigital[0])
- dataDigital[0].AddPoint(t, sinf(2*t) > 0.45);
- if (showDigital[1])
- dataDigital[1].AddPoint(t, sinf(2*t) < 0.45);
- //Analog signal values
- if (showAnalog[0])
- dataAnalog[0].AddPoint(t, sinf(2*t));
- if (showAnalog[1])
- dataAnalog[1].AddPoint(t, cosf(2*t));
- }
- ImPlot::SetNextPlotLimitsY(-1, 1);
- ImPlot::SetNextPlotLimitsX(t - 10.0, t, paused ? ImGuiCond_Once : ImGuiCond_Always);
- if (ImPlot::BeginPlot("##Digital")) {
- for (int i = 0; i < 2; ++i) {
- if (showDigital[i] && dataDigital[i].Data.size() > 0) {
- sprintf(label, "digital_%d", i);
- ImPlot::PlotDigital(label, &dataDigital[i].Data[0].x, &dataDigital[i].Data[0].y, dataDigital[i].Data.size(), dataDigital[i].Offset, 2 * sizeof(float));
- }
+ static bool paused = false;
+ static ScrollingBuffer dataDigital[2];
+ static ScrollingBuffer dataAnalog[2];
+ static bool showDigital[2] = {true, false};
+ static bool showAnalog[2] = {true, false};
+
+ char label[32];
+ ImGui::Checkbox("digital_0", &showDigital[0]); ImGui::SameLine();
+ ImGui::Checkbox("digital_1", &showDigital[1]); ImGui::SameLine();
+ ImGui::Checkbox("analog_0", &showAnalog[0]); ImGui::SameLine();
+ ImGui::Checkbox("analog_1", &showAnalog[1]);
+
+ static float t = 0;
+ if (!paused) {
+ t += ImGui::GetIO().DeltaTime;
+ //digital signal values
+ if (showDigital[0])
+ dataDigital[0].AddPoint(t, sinf(2*t) > 0.45);
+ if (showDigital[1])
+ dataDigital[1].AddPoint(t, sinf(2*t) < 0.45);
+ //Analog signal values
+ if (showAnalog[0])
+ dataAnalog[0].AddPoint(t, sinf(2*t));
+ if (showAnalog[1])
+ dataAnalog[1].AddPoint(t, cosf(2*t));
+ }
+ if (ImPlot::BeginPlot("##Digital")) {
+ ImPlot::SetupAxisLimits(ImAxis_X1, t - 10.0, t, paused ? ImGuiCond_Once : ImGuiCond_Always);
+ ImPlot::SetupAxisLimits(ImAxis_Y1, -1, 1);
+ for (int i = 0; i < 2; ++i) {
+ if (showDigital[i] && dataDigital[i].Data.size() > 0) {
+ sprintf(label, "digital_%d", i);
+ ImPlot::PlotDigital(label, &dataDigital[i].Data[0].x, &dataDigital[i].Data[0].y, dataDigital[i].Data.size(), dataDigital[i].Offset, 2 * sizeof(float));
}
- for (int i = 0; i < 2; ++i) {
- if (showAnalog[i]) {
- sprintf(label, "analog_%d", i);
- if (dataAnalog[i].Data.size() > 0)
- ImPlot::PlotLine(label, &dataAnalog[i].Data[0].x, &dataAnalog[i].Data[0].y, dataAnalog[i].Data.size(), dataAnalog[i].Offset, 2 * sizeof(float));
- }
+ }
+ for (int i = 0; i < 2; ++i) {
+ if (showAnalog[i]) {
+ sprintf(label, "analog_%d", i);
+ if (dataAnalog[i].Data.size() > 0)
+ ImPlot::PlotLine(label, &dataAnalog[i].Data[0].x, &dataAnalog[i].Data[0].y, dataAnalog[i].Data.size(), dataAnalog[i].Offset, 2 * sizeof(float));
}
- ImPlot::EndPlot();
}
+ ImPlot::EndPlot();
}
- //-------------------------------------------------------------------------
- if (ImGui::CollapsingHeader("Images")) {
- ImGui::BulletText("Below we are displaying the font texture, which is the only texture we have\naccess to in this demo.");
- ImGui::BulletText("Use the 'ImTextureID' type as storage to pass pointers or identifiers to your\nown texture data.");
- ImGui::BulletText("See ImGui Wiki page 'Image Loading and Displaying Examples'.");
- static ImVec2 bmin(0,0);
- static ImVec2 bmax(1,1);
- static ImVec2 uv0(0,0);
- static ImVec2 uv1(1,1);
- static ImVec4 tint(1,1,1,1);
- ImGui::SliderFloat2("Min", &bmin.x, -2, 2, "%.1f");
- ImGui::SliderFloat2("Max", &bmax.x, -2, 2, "%.1f");
- ImGui::SliderFloat2("UV0", &uv0.x, -2, 2, "%.1f");
- ImGui::SliderFloat2("UV1", &uv1.x, -2, 2, "%.1f");
- ImGui::ColorEdit4("Tint",&tint.x);
- if (ImPlot::BeginPlot("##image")) {
- ImPlot::PlotImage("my image",ImGui::GetIO().Fonts->TexID, bmin, bmax, uv0, uv1, tint);
- ImPlot::EndPlot();
- }
+}
+
+void ShowDemo_Images() {
+ ImGui::BulletText("Below we are displaying the font texture, which is the only texture we have\naccess to in this demo.");
+ ImGui::BulletText("Use the 'ImTextureID' type as storage to pass pointers or identifiers to your\nown texture data.");
+ ImGui::BulletText("See ImGui Wiki page 'Image Loading and Displaying Examples'.");
+ static ImVec2 bmin(0,0);
+ static ImVec2 bmax(1,1);
+ static ImVec2 uv0(0,0);
+ static ImVec2 uv1(1,1);
+ static ImVec4 tint(1,1,1,1);
+ ImGui::SliderFloat2("Min", &bmin.x, -2, 2, "%.1f");
+ ImGui::SliderFloat2("Max", &bmax.x, -2, 2, "%.1f");
+ ImGui::SliderFloat2("UV0", &uv0.x, -2, 2, "%.1f");
+ ImGui::SliderFloat2("UV1", &uv1.x, -2, 2, "%.1f");
+ ImGui::ColorEdit4("Tint",&tint.x);
+ if (ImPlot::BeginPlot("##image")) {
+ ImPlot::PlotImage("my image",ImGui::GetIO().Fonts->TexID, bmin, bmax, uv0, uv1, tint);
+ ImPlot::EndPlot();
}
- //-------------------------------------------------------------------------
- if (ImGui::CollapsingHeader("Realtime Plots")) {
- ImGui::BulletText("Move your mouse to change the data!");
- ImGui::BulletText("This example assumes 60 FPS. Higher FPS requires larger buffer size.");
- static ScrollingBuffer sdata1, sdata2;
- static RollingBuffer rdata1, rdata2;
- ImVec2 mouse = ImGui::GetMousePos();
- static float t = 0;
- t += ImGui::GetIO().DeltaTime;
- sdata1.AddPoint(t, mouse.x * 0.0005f);
- rdata1.AddPoint(t, mouse.x * 0.0005f);
- sdata2.AddPoint(t, mouse.y * 0.0005f);
- rdata2.AddPoint(t, mouse.y * 0.0005f);
+}
- static float history = 10.0f;
- ImGui::SliderFloat("History",&history,1,30,"%.1f s");
- rdata1.Span = history;
- rdata2.Span = history;
+void ShowDemo_RealtimePlots() {
+ ImGui::BulletText("Move your mouse to change the data!");
+ ImGui::BulletText("This example assumes 60 FPS. Higher FPS requires larger buffer size.");
+ static ScrollingBuffer sdata1, sdata2;
+ static RollingBuffer rdata1, rdata2;
+ ImVec2 mouse = ImGui::GetMousePos();
+ static float t = 0;
+ t += ImGui::GetIO().DeltaTime;
+ sdata1.AddPoint(t, mouse.x * 0.0005f);
+ rdata1.AddPoint(t, mouse.x * 0.0005f);
+ sdata2.AddPoint(t, mouse.y * 0.0005f);
+ rdata2.AddPoint(t, mouse.y * 0.0005f);
- static ImPlotAxisFlags flags = ImPlotAxisFlags_NoTickLabels;
- ImPlot::SetNextPlotLimitsX(t - history, t, ImGuiCond_Always);
- ImPlot::SetNextPlotLimitsY(0,1);
- if (ImPlot::BeginPlot("##Scrolling", NULL, NULL, ImVec2(-1,150), 0, flags, flags)) {
- ImPlot::SetNextFillStyle(IMPLOT_AUTO_COL,0.5f);
- ImPlot::PlotShaded("Mouse X", &sdata1.Data[0].x, &sdata1.Data[0].y, sdata1.Data.size(), -INFINITY, sdata1.Offset, 2 * sizeof(float));
- ImPlot::PlotLine("Mouse Y", &sdata2.Data[0].x, &sdata2.Data[0].y, sdata2.Data.size(), sdata2.Offset, 2*sizeof(float));
- ImPlot::EndPlot();
+ static float history = 10.0f;
+ ImGui::SliderFloat("History",&history,1,30,"%.1f s");
+ rdata1.Span = history;
+ rdata2.Span = history;
+
+ static ImPlotAxisFlags flags = ImPlotAxisFlags_NoTickLabels;
+
+ if (ImPlot::BeginPlot("##Scrolling", ImVec2(-1,150))) {
+ ImPlot::SetupAxes(NULL, NULL, flags, flags);
+ ImPlot::SetupAxisLimits(ImAxis_X1,t - history, t, ImGuiCond_Always);
+ ImPlot::SetupAxisLimits(ImAxis_Y1,0,1);
+ ImPlot::SetNextFillStyle(IMPLOT_AUTO_COL,0.5f);
+ ImPlot::PlotShaded("Mouse X", &sdata1.Data[0].x, &sdata1.Data[0].y, sdata1.Data.size(), -INFINITY, sdata1.Offset, 2 * sizeof(float));
+ ImPlot::PlotLine("Mouse Y", &sdata2.Data[0].x, &sdata2.Data[0].y, sdata2.Data.size(), sdata2.Offset, 2*sizeof(float));
+ ImPlot::EndPlot();
+ }
+ if (ImPlot::BeginPlot("##Rolling", ImVec2(-1,150))) {
+ ImPlot::SetupAxes(NULL, NULL, flags, flags);
+ ImPlot::SetupAxisLimits(ImAxis_X1,0,history, ImGuiCond_Always);
+ ImPlot::SetupAxisLimits(ImAxis_Y1,0,1);
+ ImPlot::PlotLine("Mouse X", &rdata1.Data[0].x, &rdata1.Data[0].y, rdata1.Data.size(), 0, 2 * sizeof(float));
+ ImPlot::PlotLine("Mouse Y", &rdata2.Data[0].x, &rdata2.Data[0].y, rdata2.Data.size(), 0, 2 * sizeof(float));
+ ImPlot::EndPlot();
+ }
+}
+
+void ShowDemo_MarkersAndText() {
+ static float mk_size = ImPlot::GetStyle().MarkerSize;
+ static float mk_weight = ImPlot::GetStyle().MarkerWeight;
+ ImGui::DragFloat("Marker Size",&mk_size,0.1f,2.0f,10.0f,"%.2f px");
+ ImGui::DragFloat("Marker Weight", &mk_weight,0.05f,0.5f,3.0f,"%.2f px");
+
+ if (ImPlot::BeginPlot("##MarkerStyles", ImVec2(-1,0), ImPlotFlags_CanvasOnly)) {
+
+ ImPlot::SetupAxes(NULL, NULL, ImPlotAxisFlags_NoDecorations, ImPlotAxisFlags_NoDecorations);
+ ImPlot::SetupAxesLimits(0, 10, 0, 12);
+
+ ImS8 xs[2] = {1,4};
+ ImS8 ys[2] = {10,11};
+
+ // filled markers
+ for (int m = 0; m < ImPlotMarker_COUNT; ++m) {
+ ImGui::PushID(m);
+ ImPlot::SetNextMarkerStyle(m, mk_size, IMPLOT_AUTO_COL, mk_weight);
+ ImPlot::PlotLine("##Filled", xs, ys, 2);
+ ImGui::PopID();
+ ys[0]--; ys[1]--;
}
- ImPlot::SetNextPlotLimitsX(0, history, ImGuiCond_Always);
- ImPlot::SetNextPlotLimitsY(0,1);
- if (ImPlot::BeginPlot("##Rolling", NULL, NULL, ImVec2(-1,150), 0, flags, flags)) {
- ImPlot::PlotLine("Mouse X", &rdata1.Data[0].x, &rdata1.Data[0].y, rdata1.Data.size(), 0, 2 * sizeof(float));
- ImPlot::PlotLine("Mouse Y", &rdata2.Data[0].x, &rdata2.Data[0].y, rdata2.Data.size(), 0, 2 * sizeof(float));
- ImPlot::EndPlot();
+ xs[0] = 6; xs[1] = 9; ys[0] = 10; ys[1] = 11;
+ // open markers
+ for (int m = 0; m < ImPlotMarker_COUNT; ++m) {
+ ImGui::PushID(m);
+ ImPlot::SetNextMarkerStyle(m, mk_size, ImVec4(0,0,0,0), mk_weight);
+ ImPlot::PlotLine("##Open", xs, ys, 2);
+ ImGui::PopID();
+ ys[0]--; ys[1]--;
}
+
+ ImPlot::PlotText("Filled Markers", 2.5f, 6.0f);
+ ImPlot::PlotText("Open Markers", 7.5f, 6.0f);
+
+ ImPlot::PushStyleColor(ImPlotCol_InlayText, ImVec4(1,0,1,1));
+ ImPlot::PlotText("Vertical Text", 5.0f, 6.0f, true);
+ ImPlot::PopStyleColor();
+
+ ImPlot::EndPlot();
}
- //-------------------------------------------------------------------------
- if (ImGui::CollapsingHeader("Markers and Text")) {
- static float mk_size = ImPlot::GetStyle().MarkerSize;
- static float mk_weight = ImPlot::GetStyle().MarkerWeight;
- ImGui::DragFloat("Marker Size",&mk_size,0.1f,2.0f,10.0f,"%.2f px");
- ImGui::DragFloat("Marker Weight", &mk_weight,0.05f,0.5f,3.0f,"%.2f px");
+}
- ImPlot::SetNextPlotLimits(0, 10, 0, 12);
- if (ImPlot::BeginPlot("##MarkerStyles", NULL, NULL, ImVec2(-1,0), ImPlotFlags_CanvasOnly, ImPlotAxisFlags_NoDecorations, ImPlotAxisFlags_NoDecorations)) {
- ImS8 xs[2] = {1,4};
- ImS8 ys[2] = {10,11};
+void ShowDemo_LogAxes() {
+ static double xs[1001], ys1[1001], ys2[1001], ys3[1001];
+ for (int i = 0; i < 1001; ++i) {
+ xs[i] = i*0.1f;
+ ys1[i] = sin(xs[i]) + 1;
+ ys2[i] = log(xs[i]);
+ ys3[i] = pow(10.0, xs[i]);
+ }
+ ImGui::BulletText("Open the plot context menu (right click) to change scales.");
- // filled markers
- for (int m = 0; m < ImPlotMarker_COUNT; ++m) {
- ImGui::PushID(m);
- ImPlot::SetNextMarkerStyle(m, mk_size, IMPLOT_AUTO_COL, mk_weight);
- ImPlot::PlotLine("##Filled", xs, ys, 2);
- ImGui::PopID();
- ys[0]--; ys[1]--;
- }
- xs[0] = 6; xs[1] = 9; ys[0] = 10; ys[1] = 11;
- // open markers
- for (int m = 0; m < ImPlotMarker_COUNT; ++m) {
- ImGui::PushID(m);
- ImPlot::SetNextMarkerStyle(m, mk_size, ImVec4(0,0,0,0), mk_weight);
- ImPlot::PlotLine("##Open", xs, ys, 2);
- ImGui::PopID();
- ys[0]--; ys[1]--;
- }
+ if (ImPlot::BeginPlot("Log Plot", ImVec2(-1,0))) {
+ ImPlot::SetupAxis(ImAxis_X1, NULL, ImPlotAxisFlags_LogScale);
+ ImPlot::SetupAxesLimits(0.1, 100, 0, 10);
+ ImPlot::PlotLine("f(x) = x", xs, xs, 1001);
+ ImPlot::PlotLine("f(x) = sin(x)+1", xs, ys1, 1001);
+ ImPlot::PlotLine("f(x) = log(x)", xs, ys2, 1001);
+ ImPlot::PlotLine("f(x) = 10^x", xs, ys3, 21);
+ ImPlot::EndPlot();
+ }
+}
- ImPlot::PlotText("Filled Markers", 2.5f, 6.0f);
- ImPlot::PlotText("Open Markers", 7.5f, 6.0f);
+void ShowDemo_TimeAxes() {
- ImPlot::PushStyleColor(ImPlotCol_InlayText, ImVec4(1,0,1,1));
- ImPlot::PlotText("Vertical Text", 5.0f, 6.0f, true);
- ImPlot::PopStyleColor();
+ static double t_min = 1609459200; // 01/01/2021 @ 12:00:00am (UTC)
+ static double t_max = 1640995200; // 01/01/2022 @ 12:00:00am (UTC)
- ImPlot::EndPlot();
+ ImGui::BulletText("When ImPlotAxisFlags_Time is enabled on the X-Axis, values are interpreted as\n"
+ "UNIX timestamps in seconds and axis labels are formated as date/time.");
+ ImGui::BulletText("By default, labels are in UTC time but can be set to use local time instead.");
+
+ ImGui::Checkbox("Local Time",&ImPlot::GetStyle().UseLocalTime);
+ ImGui::SameLine();
+ ImGui::Checkbox("ISO 8601",&ImPlot::GetStyle().UseISO8601);
+ ImGui::SameLine();
+ ImGui::Checkbox("24 Hour Clock",&ImPlot::GetStyle().Use24HourClock);
+
+ static HugeTimeData* data = NULL;
+ if (data == NULL) {
+ ImGui::SameLine();
+ if (ImGui::Button("Generate Huge Data (~500MB!)")) {
+ static HugeTimeData sdata(t_min);
+ data = &sdata;
}
}
- //-------------------------------------------------------------------------
- if (ImGui::CollapsingHeader("Log Scale")) {
- static double xs[1001], ys1[1001], ys2[1001], ys3[1001];
- for (int i = 0; i < 1001; ++i) {
- xs[i] = i*0.1f;
- ys1[i] = sin(xs[i]) + 1;
- ys2[i] = log(xs[i]);
- ys3[i] = pow(10.0, xs[i]);
- }
- ImGui::BulletText("Open the plot context menu (right click) to change scales.");
- ImPlot::SetNextPlotLimits(0.1, 100, 0, 10);
- if (ImPlot::BeginPlot("Log Plot", NULL, NULL, ImVec2(-1,0), 0, ImPlotAxisFlags_LogScale )) {
- ImPlot::PlotLine("f(x) = x", xs, xs, 1001);
- ImPlot::PlotLine("f(x) = sin(x)+1", xs, ys1, 1001);
- ImPlot::PlotLine("f(x) = log(x)", xs, ys2, 1001);
- ImPlot::PlotLine("f(x) = 10^x", xs, ys3, 21);
- ImPlot::EndPlot();
+ if (ImPlot::BeginPlot("##Time", ImVec2(-1,0))) {
+ ImPlot::SetupAxis(ImAxis_X1, NULL, ImPlotAxisFlags_Time);
+ ImPlot::SetupAxesLimits(t_min,t_max,0,1);
+ if (data != NULL) {
+ // downsample our data
+ int downsample = (int)ImPlot::GetPlotLimits().X.Size() / 1000 + 1;
+ int start = (int)(ImPlot::GetPlotLimits().X.Min - t_min);
+ start = start < 0 ? 0 : start > HugeTimeData::Size - 1 ? HugeTimeData::Size - 1 : start;
+ int end = (int)(ImPlot::GetPlotLimits().X.Max - t_min) + 1000;
+ end = end < 0 ? 0 : end > HugeTimeData::Size - 1 ? HugeTimeData::Size - 1 : end;
+ int size = (end - start)/downsample;
+ // plot it
+ ImPlot::PlotLine("Time Series", &data->Ts[start], &data->Ys[start], size, 0, sizeof(double)*downsample);
}
+ // plot time now
+ double t_now = (double)time(0);
+ double y_now = HugeTimeData::GetY(t_now);
+ ImPlot::PlotScatter("Now",&t_now,&y_now,1);
+ ImPlot::Annotation(t_now,y_now,ImPlot::GetLastItemColor(),ImVec2(10,10),false,"Now");
+ ImPlot::EndPlot();
}
- if (ImGui::CollapsingHeader("Time Formatted Axes")) {
+}
- static double t_min = 1609459200; // 01/01/2021 @ 12:00:00am (UTC)
- static double t_max = 1640995200; // 01/01/2022 @ 12:00:00am (UTC)
+void ShowDemo_MultipleAxes() {
+ static float xs[1001], xs2[1001], ys1[1001], ys2[1001], ys3[1001];
+ for (int i = 0; i < 1001; ++i) {
+ xs[i] = (i*0.1f);
+ xs2[i] = xs[i] + 10.0f;
+ ys1[i] = sinf(xs[i]) * 3 + 1;
+ ys2[i] = cosf(xs[i]) * 0.2f + 0.5f;
+ ys3[i] = sinf(xs[i]+0.5f) * 100 + 200;
+ }
- ImGui::BulletText("When ImPlotAxisFlags_Time is enabled on the X-Axis, values are interpreted as\n"
- "UNIX timestamps in seconds and axis labels are formated as date/time.");
- ImGui::BulletText("By default, labels are in UTC time but can be set to use local time instead.");
+ static bool x2_axis = true;
+ static bool y2_axis = true;
+ static bool y3_axis = true;
- ImGui::Checkbox("Local Time",&ImPlot::GetStyle().UseLocalTime);
- ImGui::SameLine();
- ImGui::Checkbox("ISO 8601",&ImPlot::GetStyle().UseISO8601);
- ImGui::SameLine();
- ImGui::Checkbox("24 Hour Clock",&ImPlot::GetStyle().Use24HourClock);
+ ImGui::Checkbox("X-Axis 2", &x2_axis);
+ ImGui::SameLine();
+ ImGui::Checkbox("Y-Axis 2", &y2_axis);
+ ImGui::SameLine();
+ ImGui::Checkbox("Y-Axis 3", &y3_axis);
- static HugeTimeData* data = NULL;
- if (data == NULL) {
- ImGui::SameLine();
- if (ImGui::Button("Generate Huge Data (~500MB!)")) {
- static HugeTimeData sdata(t_min);
- data = &sdata;
- }
- }
+ ImGui::BulletText("You can drag axes to the opposite side of the plot.");
+ ImGui::BulletText("Hover over legend items to see which axis they are plotted on.");
- ImPlot::SetNextPlotLimits(t_min,t_max,0,1);
- if (ImPlot::BeginPlot("##Time", NULL, NULL, ImVec2(-1,0), 0, ImPlotAxisFlags_Time)) {
- if (data != NULL) {
- // downsample our data
- int downsample = (int)ImPlot::GetPlotLimits().X.Size() / 1000 + 1;
- int start = (int)(ImPlot::GetPlotLimits().X.Min - t_min);
- start = start < 0 ? 0 : start > HugeTimeData::Size - 1 ? HugeTimeData::Size - 1 : start;
- int end = (int)(ImPlot::GetPlotLimits().X.Max - t_min) + 1000;
- end = end < 0 ? 0 : end > HugeTimeData::Size - 1 ? HugeTimeData::Size - 1 : end;
- int size = (end - start)/downsample;
- // plot it
- ImPlot::PlotLine("Time Series", &data->Ts[start], &data->Ys[start], size, 0, sizeof(double)*downsample);
- }
- // plot time now
- double t_now = (double)time(0);
- double y_now = HugeTimeData::GetY(t_now);
- ImPlot::PlotScatter("Now",&t_now,&y_now,1);
- ImPlot::Annotate(t_now,y_now,ImVec2(10,10),ImPlot::GetLastItemColor(),"Now");
- ImPlot::EndPlot();
+ if (ImPlot::BeginPlot("Multi-Axis Plot", ImVec2(-1,0))) {
+ ImPlot::SetupAxes("X-Axis 1", "Y-Axis 1");
+ ImPlot::SetupAxesLimits(0, 100, 0, 10);
+ if (x2_axis) {
+ ImPlot::SetupAxis(ImAxis_X2, "X-Axis 2",ImPlotAxisFlags_AuxDefault);
+ ImPlot::SetupAxisLimits(ImAxis_X2, 0, 100);
}
- }
- //-------------------------------------------------------------------------
- if (ImGui::CollapsingHeader("Multiple Y-Axes")) {
- static float xs[1001], xs2[1001], ys1[1001], ys2[1001], ys3[1001];
- for (int i = 0; i < 1001; ++i) {
- xs[i] = (i*0.1f);
- ys1[i] = sinf(xs[i]) * 3 + 1;
- ys2[i] = cosf(xs[i]) * 0.2f + 0.5f;
- ys3[i] = sinf(xs[i]+0.5f) * 100 + 200;
- xs2[i] = xs[i] + 10.0f;
+ if (y2_axis) {
+ ImPlot::SetupAxis(ImAxis_Y2, "Y-Axis 2",ImPlotAxisFlags_AuxDefault);
+ ImPlot::SetupAxisLimits(ImAxis_Y2, 0, 1);
+ }
+ if (y3_axis) {
+ ImPlot::SetupAxis(ImAxis_Y3, "Y-Axis 3",ImPlotAxisFlags_AuxDefault);
+ ImPlot::SetupAxisLimits(ImAxis_Y3, 0, 300);
}
- static bool y2_axis = true;
- static bool y3_axis = true;
- ImGui::Checkbox("Y-Axis 2", &y2_axis);
- ImGui::SameLine();
- ImGui::Checkbox("Y-Axis 3", &y3_axis);
- ImGui::SameLine();
-
- // you can fit axes programatically
- ImGui::SameLine(); if (ImGui::Button("Fit X")) ImPlot::FitNextPlotAxes(true, false, false, false);
- ImGui::SameLine(); if (ImGui::Button("Fit Y")) ImPlot::FitNextPlotAxes(false, true, false, false);
- ImGui::SameLine(); if (ImGui::Button("Fit Y2")) ImPlot::FitNextPlotAxes(false, false, true, false);
- ImGui::SameLine(); if (ImGui::Button("Fit Y3")) ImPlot::FitNextPlotAxes(false, false, false, true);
- ImPlot::SetNextPlotLimits(0.1, 100, 0, 10);
- ImPlot::SetNextPlotLimitsY(0, 1, ImGuiCond_Once, 1);
- ImPlot::SetNextPlotLimitsY(0, 300, ImGuiCond_Once, 2);
- if (ImPlot::BeginPlot("Multi-Axis Plot", NULL, "Y-Axis 1", ImVec2(-1,0),
- (y2_axis ? ImPlotFlags_YAxis2 : 0) |
- (y3_axis ? ImPlotFlags_YAxis3 : 0),
- ImPlotAxisFlags_None, ImPlotAxisFlags_None, ImPlotAxisFlags_NoGridLines, ImPlotAxisFlags_NoGridLines,
- "Y-Axis 2", "Y-Axis 3")) {
- ImPlot::PlotLine("f(x) = x", xs, xs, 1001);
- ImPlot::PlotLine("f(x) = sin(x)*3+1", xs, ys1, 1001);
- if (y2_axis) {
- ImPlot::SetPlotYAxis(ImPlotYAxis_2);
- ImPlot::PlotLine("f(x) = cos(x)*.2+.5 (Y2)", xs, ys2, 1001);
- }
- if (y3_axis) {
- ImPlot::SetPlotYAxis(ImPlotYAxis_3);
- ImPlot::PlotLine("f(x) = sin(x+.5)*100+200 (Y3)", xs2, ys3, 1001);
- }
- ImPlot::EndPlot();
+ ImPlot::PlotLine("f(x) = x", xs, xs, 1001);
+ if (x2_axis) {
+ ImPlot::SetAxes(ImAxis_X2, ImAxis_Y1);
+ ImPlot::PlotLine("f(x) = sin(x)*3+1", xs2, ys1, 1001);
+ }
+ if (y2_axis) {
+ ImPlot::SetAxes(ImAxis_X1, ImAxis_Y2);
+ ImPlot::PlotLine("f(x) = cos(x)*.2+.5", xs, ys2, 1001);
}
+ if (y3_axis) {
+ ImPlot::SetAxes(ImAxis_X2, ImAxis_Y3);
+ ImPlot::PlotLine("f(x) = sin(x+.5)*100+200 ", xs2, ys3, 1001);
+ }
+ ImPlot::EndPlot();
}
- //-------------------------------------------------------------------------
- if (ImGui::CollapsingHeader("Linked Axes")) {
- static double xmin = 0, xmax = 1, ymin = 0, ymax = 1;
- static bool linkx = true, linky = true;
- int data[2] = {0,1};
- ImGui::Checkbox("Link X", &linkx);
- ImGui::SameLine();
- ImGui::Checkbox("Link Y", &linky);
- ImPlot::LinkNextPlotLimits(linkx ? &xmin : NULL , linkx ? &xmax : NULL, linky ? &ymin : NULL, linky ? &ymax : NULL);
+}
+
+void ShowDemo_LinkedAxes() {
+ static ImPlotRect lims(0,1,0,1);
+ static bool linkx = true, linky = true;
+ int data[2] = {0,1};
+ ImGui::Checkbox("Link X", &linkx);
+ ImGui::SameLine();
+ ImGui::Checkbox("Link Y", &linky);
+
+ ImGui::DragScalarN("Limits",ImGuiDataType_Double,&lims.X.Min,4,0.01f);
+
+ if (BeginAlignedPlots("AlignedGroup")) {
if (ImPlot::BeginPlot("Plot A")) {
+ ImPlot::SetupAxisLinks(ImAxis_X1, linkx ? &lims.X.Min : NULL, linkx ? &lims.X.Max : NULL);
+ ImPlot::SetupAxisLinks(ImAxis_Y1, linky ? &lims.Y.Min : NULL, linky ? &lims.Y.Max : NULL);
ImPlot::PlotLine("Line",data,2);
ImPlot::EndPlot();
}
- ImPlot::LinkNextPlotLimits(linkx ? &xmin : NULL , linkx ? &xmax : NULL, linky ? &ymin : NULL, linky ? &ymax : NULL);
if (ImPlot::BeginPlot("Plot B")) {
+ ImPlot::SetupAxisLinks(ImAxis_X1, linkx ? &lims.X.Min : NULL, linkx ? &lims.X.Max : NULL);
+ ImPlot::SetupAxisLinks(ImAxis_Y1, linky ? &lims.Y.Min : NULL, linky ? &lims.Y.Max : NULL);
ImPlot::PlotLine("Line",data,2);
ImPlot::EndPlot();
}
+ ImPlot::EndAlignedPlots();
}
- //-------------------------------------------------------------------------
- if (ImGui::CollapsingHeader("Equal Axes")) {
- static double xs[1000], ys[1000];
- for (int i = 0; i < 1000; ++i) {
- double angle = i * 2 * PI / 999.0;
- xs[i] = cos(angle); ys[i] = sin(angle);
- }
- if (ImPlot::BeginPlot("",0,0,ImVec2(-1,0),ImPlotFlags_Equal)) {
- ImPlot::PlotLine("Circle",xs,ys,1000);
- ImPlot::EndPlot();
- }
+}
+
+void ShowDemo_EqualAxes() {
+ ImGui::BulletText("Equal constraint applies to axis pairs (e.g ImAxis_X1/Y1, ImAxis_X2/Y2");
+ static double xs1[360], ys1[360];
+ for (int i = 0; i < 360; ++i) {
+ double angle = i * 2 * PI / 359.0;
+ xs1[i] = cos(angle); ys1[i] = sin(angle);
}
- //-------------------------------------------------------------------------
- if (ImGui::CollapsingHeader("Auto-Fitting Data")) {
+ float xs2[] = {-1,0,1,0,-1};
+ float ys2[] = {0,1,0,-1,0};
+ if (ImPlot::BeginPlot("##EqualAxes",ImVec2(-1,0),ImPlotFlags_Equal)) {
+ ImPlot::SetupAxis(ImAxis_X2, NULL, ImPlotAxisFlags_AuxDefault);
+ ImPlot::SetupAxis(ImAxis_Y2, NULL, ImPlotAxisFlags_AuxDefault);
+ ImPlot::PlotLine("Circle",xs1,ys1,360);
+ ImPlot::SetAxes(ImAxis_X2, ImAxis_Y2);
+ ImPlot::PlotLine("Diamond",xs2,ys2,5);
+ ImPlot::EndPlot();
+ }
+}
- ImGui::BulletText("The Y-axis has been configured to auto-fit to only the data visible in X-axis range.");
- ImGui::BulletText("Zoom and pan the X-axis. Disable Stems to see a difference in fit.");
- ImGui::BulletText("If ImPlotAxisFlags_RangeFit is disabled, the axis will fit ALL data.");
+void ShowDemo_AutoFittingData() {
+ ImGui::BulletText("The Y-axis has been configured to auto-fit to only the data visible in X-axis range.");
+ ImGui::BulletText("Zoom and pan the X-axis. Disable Stems to see a difference in fit.");
+ ImGui::BulletText("If ImPlotAxisFlags_RangeFit is disabled, the axis will fit ALL data.");
- static ImPlotAxisFlags xflags = ImPlotAxisFlags_None;
- static ImPlotAxisFlags yflags = ImPlotAxisFlags_AutoFit|ImPlotAxisFlags_RangeFit;
+ static ImPlotAxisFlags xflags = ImPlotAxisFlags_None;
+ static ImPlotAxisFlags yflags = ImPlotAxisFlags_AutoFit|ImPlotAxisFlags_RangeFit;
- ImGui::TextUnformatted("X: "); ImGui::SameLine();
- ImGui::CheckboxFlags("ImPlotAxisFlags_AutoFit##X", (unsigned int*)&xflags, ImPlotAxisFlags_AutoFit); ImGui::SameLine();
- ImGui::CheckboxFlags("ImPlotAxisFlags_RangeFit##X", (unsigned int*)&xflags, ImPlotAxisFlags_RangeFit);
+ ImGui::TextUnformatted("X: "); ImGui::SameLine();
+ ImGui::CheckboxFlags("ImPlotAxisFlags_AutoFit##X", (unsigned int*)&xflags, ImPlotAxisFlags_AutoFit); ImGui::SameLine();
+ ImGui::CheckboxFlags("ImPlotAxisFlags_RangeFit##X", (unsigned int*)&xflags, ImPlotAxisFlags_RangeFit);
- ImGui::TextUnformatted("Y: "); ImGui::SameLine();
- ImGui::CheckboxFlags("ImPlotAxisFlags_AutoFit##Y", (unsigned int*)&yflags, ImPlotAxisFlags_AutoFit); ImGui::SameLine();
- ImGui::CheckboxFlags("ImPlotAxisFlags_RangeFit##Y", (unsigned int*)&yflags, ImPlotAxisFlags_RangeFit);
+ ImGui::TextUnformatted("Y: "); ImGui::SameLine();
+ ImGui::CheckboxFlags("ImPlotAxisFlags_AutoFit##Y", (unsigned int*)&yflags, ImPlotAxisFlags_AutoFit); ImGui::SameLine();
+ ImGui::CheckboxFlags("ImPlotAxisFlags_RangeFit##Y", (unsigned int*)&yflags, ImPlotAxisFlags_RangeFit);
- static double data[101];
- srand(0);
- for (int i = 0; i < 101; ++i)
- data[i] = 1 + sin(i/10.0f);
+ static double data[101];
+ srand(0);
+ for (int i = 0; i < 101; ++i)
+ data[i] = 1 + sin(i/10.0f);
- if (ImPlot::BeginPlot("##DataFitting","X","Y",ImVec2(-1,0),0,xflags,yflags)) {
- ImPlot::PlotLine("Line",data,101);
- ImPlot::PlotStems("Stems",data,101);
- ImPlot::EndPlot();
- };
- }
- //-------------------------------------------------------------------------
- if (ImGui::CollapsingHeader("Querying")) {
- static ImVector<ImPlotPoint> data;
- static ImPlotLimits range, query, select;
+ if (ImPlot::BeginPlot("##DataFitting")) {
+ ImPlot::SetupAxes("X","Y",xflags,yflags);
+ ImPlot::PlotLine("Line",data,101);
+ ImPlot::PlotStems("Stems",data,101);
+ ImPlot::EndPlot();
+ };
+}
+
+ImPlotPoint SinewaveGetter(void* data, int i) {
+ float f = *(float*)data;
+ return ImPlotPoint(i,sinf(f*i));
+}
- ImGui::BulletText("Ctrl + click in the plot area to draw points.");
- ImGui::BulletText("Middle click (or Ctrl + right click) and drag to create a query rect.");
- ImGui::Indent();
- ImGui::BulletText("Hold Alt to expand query horizontally.");
- ImGui::BulletText("Hold Shift to expand query vertically.");
- ImGui::BulletText("The query rect can be dragged after it's created.");
- ImGui::Unindent();
+void ShowDemo_SubplotsSizing() {
- if (ImPlot::BeginPlot("##Drawing", NULL, NULL, ImVec2(-1,0), ImPlotFlags_Query, ImPlotAxisFlags_NoDecorations, ImPlotAxisFlags_NoDecorations)) {
- if (ImPlot::IsPlotHovered() && ImGui::IsMouseClicked(0) && ImGui::GetIO().KeyCtrl) {
- ImPlotPoint pt = ImPlot::GetPlotMousePos();
- data.push_back(pt);
+ static ImPlotSubplotFlags flags = ImPlotSubplotFlags_None;
+ ImGui::CheckboxFlags("ImPlotSubplotFlags_NoResize", (unsigned int*)&flags, ImPlotSubplotFlags_NoResize);
+ ImGui::CheckboxFlags("ImPlotSubplotFlags_NoTitle", (unsigned int*)&flags, ImPlotSubplotFlags_NoTitle);
+
+ static int rows = 3;
+ static int cols = 3;
+ ImGui::SliderInt("Rows",&rows,1,5);
+ ImGui::SliderInt("Cols",&cols,1,5);
+ static float rratios[] = {5,1,1,1,1,1};
+ static float cratios[] = {5,1,1,1,1,1};
+ ImGui::DragScalarN("Row Ratios",ImGuiDataType_Float,rratios,rows,0.01f,0);
+ ImGui::DragScalarN("Col Ratios",ImGuiDataType_Float,cratios,cols,0.01f,0);
+ if (ImPlot::BeginSubplots("My Subplots", rows, cols, ImVec2(-1,400), flags, rratios, cratios)) {
+ for (int i = 0; i < rows*cols; ++i) {
+ if (ImPlot::BeginPlot("",ImVec2(),ImPlotFlags_NoLegend)) {
+ ImPlot::SetupAxes(NULL,NULL,ImPlotAxisFlags_NoDecorations,ImPlotAxisFlags_NoDecorations);
+ float fi = 0.01f * (i+1);
+ ImPlot::SetNextLineStyle(SampleColormap((float)i/(float)(rows*cols-1),ImPlotColormap_Jet));
+ ImPlot::PlotLineG("data",SinewaveGetter,&fi,1000);
+ ImPlot::EndPlot();
}
- if (data.size() > 0)
- ImPlot::PlotScatter("Points", &data[0].x, &data[0].y, data.size(), 0, 2 * sizeof(double));
- if (ImPlot::IsPlotQueried() && data.size() > 0) {
- ImPlotLimits range2 = ImPlot::GetPlotQuery();
- int cnt = 0;
- ImPlotPoint avg;
- for (int i = 0; i < data.size(); ++i) {
- if (range2.Contains(data[i].x, data[i].y)) {
- avg.x += data[i].x;
- avg.y += data[i].y;
- cnt++;
+ }
+ ImPlot::EndSubplots();
+ }
+}
+
+void ShowDemo_SubplotItemSharing() {
+ static ImPlotSubplotFlags flags = ImPlotSubplotFlags_ShareItems;
+ ImGui::CheckboxFlags("ImPlotSubplotFlags_ShareItems", (unsigned int*)&flags, ImPlotSubplotFlags_ShareItems);
+ ImGui::CheckboxFlags("ImPlotSubplotFlags_ColMajor", (unsigned int*)&flags, ImPlotSubplotFlags_ColMajor);
+ ImGui::BulletText("Drag and drop items from the legend onto plots (except for 'common')");
+ static int rows = 2;
+ static int cols = 3;
+ static int id[] = {0,1,2,3,4,5};
+ static int curj = -1;
+ if (ImPlot::BeginSubplots("##ItemSharing", rows, cols, ImVec2(-1,400), flags)) {
+ for (int i = 0; i < rows*cols; ++i) {
+ if (ImPlot::BeginPlot("")) {
+ float fc = 0.01f;
+ ImPlot::PlotLineG("common",SinewaveGetter,&fc,1000);
+ for (int j = 0; j < 6; ++j) {
+ if (id[j] == i) {
+ char label[8];
+ float fj = 0.01f * (j+2);
+ sprintf(label, "data%d", j);
+ ImPlot::PlotLineG(label,SinewaveGetter,&fj,1000);
+ if (ImPlot::BeginDragDropSourceItem(label)) {
+ curj = j;
+ ImGui::SetDragDropPayload("MY_DND",NULL,0);
+ ImPlot::ItemIcon(GetLastItemColor()); ImGui::SameLine();
+ ImGui::TextUnformatted(label);
+ ImPlot::EndDragDropSource();
+ }
}
}
- if (cnt > 0) {
- avg.x = avg.x / cnt;
- avg.y = avg.y / cnt;
- ImPlot::SetNextMarkerStyle(ImPlotMarker_Square);
- ImPlot::PlotScatter("Average", &avg.x, &avg.y, 1);
+ if (ImPlot::BeginDragDropTargetPlot()) {
+ if (ImGui::AcceptDragDropPayload("MY_DND"))
+ id[curj] = i;
+ ImPlot::EndDragDropTarget();
}
+ ImPlot::EndPlot();
}
- range = ImPlot::GetPlotLimits();
- query = ImPlot::GetPlotQuery();
- select = ImPlot::GetPlotSelection();
- ImPlot::EndPlot();
}
- ImGui::Text("Limits: [%g,%g,%g,%g]", range.X.Min, range.X.Max, range.Y.Min, range.Y.Max);
- ImGui::Text("Query: [%g,%g,%g,%g]", query.X.Min, query.X.Max, query.Y.Min, query.Y.Max);
- ImGui::Text("Selection: [%g,%g,%g,%g]", select.X.Min, select.X.Max, select.Y.Min, select.Y.Max);
+ ImPlot::EndSubplots();
+ }
+}
- ImGui::Separator();
+void ShowDemo_SubplotAxisLinking() {
+ static ImPlotSubplotFlags flags = ImPlotSubplotFlags_LinkRows | ImPlotSubplotFlags_LinkCols;
+ ImGui::CheckboxFlags("ImPlotSubplotFlags_LinkRows", (unsigned int*)&flags, ImPlotSubplotFlags_LinkRows);
+ ImGui::CheckboxFlags("ImPlotSubplotFlags_LinkCols", (unsigned int*)&flags, ImPlotSubplotFlags_LinkCols);
+ ImGui::CheckboxFlags("ImPlotSubplotFlags_LinkAllX", (unsigned int*)&flags, ImPlotSubplotFlags_LinkAllX);
+ ImGui::CheckboxFlags("ImPlotSubplotFlags_LinkAllY", (unsigned int*)&flags, ImPlotSubplotFlags_LinkAllY);
- // mimic's soulthread's imgui_plot demo
- static float x_data[512];
- static float y_data1[512];
- static float y_data2[512];
- static float y_data3[512];
- static float sampling_freq = 44100;
- static float freq = 500;
- for (size_t i = 0; i < 512; ++i) {
- const float t = i / sampling_freq;
- x_data[i] = t;
- const float arg = 2 * 3.14f * freq * t;
- y_data1[i] = sinf(arg);
- y_data2[i] = y_data1[i] * -0.6f + sinf(2 * arg) * 0.4f;
- y_data3[i] = y_data2[i] * -0.6f + sinf(3 * arg) * 0.4f;
+ static int rows = 2;
+ static int cols = 2;
+ if (ImPlot::BeginSubplots("##AxisLinking", rows, cols, ImVec2(-1,400), flags)) {
+ for (int i = 0; i < rows*cols; ++i) {
+ if (ImPlot::BeginPlot("")) {
+ ImPlot::SetupAxesLimits(0,1000,-1,1);
+ float fc = 0.01f;
+ ImPlot::PlotLineG("common",SinewaveGetter,&fc,1000);
+ ImPlot::EndPlot();
+ }
}
- ImGui::BulletText("Query the first plot to render a subview in the second plot (see above for controls).");
- ImPlotAxisFlags flags = ImPlotAxisFlags_NoTickLabels;
- static bool use_selection = false;
- ImGui::Checkbox("Use Box Selection",&use_selection);
- bool is_viewed = false;
- ImPlotLimits view;
- ImPlot::SetNextPlotLimits(0,0.01,-1,1);
- if (ImPlot::BeginPlot("##View1",NULL,NULL,ImVec2(-1,150), ImPlotFlags_Query, flags, flags)) {
- ImPlot::PlotLine("Signal 1", x_data, y_data1, 512);
- ImPlot::PlotLine("Signal 2", x_data, y_data2, 512);
- ImPlot::PlotLine("Signal 3", x_data, y_data3, 512);
- is_viewed = use_selection ? ImPlot::IsPlotSelected() : ImPlot::IsPlotQueried();
- view = use_selection ? ImPlot::GetPlotSelection() : ImPlot::GetPlotQuery();
- ImPlot::EndPlot();
+ ImPlot::EndSubplots();
+ }
+}
+
+
+void ShowDemo_LegendOptions() {
+ static ImPlotLocation loc = ImPlotLocation_East;
+ static bool h = false; static bool o = true;
+ ImGui::CheckboxFlags("North", (unsigned int*)&loc, ImPlotLocation_North); ImGui::SameLine();
+ ImGui::CheckboxFlags("South", (unsigned int*)&loc, ImPlotLocation_South); ImGui::SameLine();
+ ImGui::CheckboxFlags("West", (unsigned int*)&loc, ImPlotLocation_West); ImGui::SameLine();
+ ImGui::CheckboxFlags("East", (unsigned int*)&loc, ImPlotLocation_East); ImGui::SameLine();
+ ImGui::Checkbox("Horizontal##2", &h); ImGui::SameLine();
+ ImGui::Checkbox("Outside", &o);
+
+ ImGui::SliderFloat2("LegendPadding", (float*)&GetStyle().LegendPadding, 0.0f, 20.0f, "%.0f");
+ ImGui::SliderFloat2("LegendInnerPadding", (float*)&GetStyle().LegendInnerPadding, 0.0f, 10.0f, "%.0f");
+ ImGui::SliderFloat2("LegendSpacing", (float*)&GetStyle().LegendSpacing, 0.0f, 5.0f, "%.0f");
+
+ if (ImPlot::BeginPlot("##Legend",ImVec2(-1,0))) {
+ ImPlotLegendFlags flags = ImPlotLegendFlags_None;
+ if (h) flags |= ImPlotLegendFlags_Horizontal;
+ if (o) flags |= ImPlotLegendFlags_Outside;
+ ImPlot::SetupLegend(loc, flags);
+ static MyImPlot::WaveData data1(0.001, 0.2, 2, 0.75);
+ static MyImPlot::WaveData data2(0.001, 0.2, 4, 0.25);
+ static MyImPlot::WaveData data3(0.001, 0.2, 6, 0.5);
+ ImPlot::PlotLineG("Item 1", MyImPlot::SineWave, &data1, 1000); // "Item 1" added to legend
+ ImPlot::PlotLineG("Item 2##IDText", MyImPlot::SawWave, &data2, 1000); // "Item 2" added to legend, text after ## used for ID only
+ ImPlot::PlotLineG("##NotListed", MyImPlot::SawWave, &data3, 1000); // plotted, but not added to legend
+ ImPlot::PlotLineG("Item 3", MyImPlot::SineWave, &data1, 1000); // "Item 3" added to legend
+ ImPlot::PlotLineG("Item 3", MyImPlot::SawWave, &data2, 1000); // combined with previous "Item 3"
+ ImPlot::EndPlot();
+ }
+}
+
+void ShowDemo_DragPoints() {
+ ImGui::BulletText("Click and drag each point.");
+ static ImPlotDragToolFlags flags = ImPlotDragToolFlags_None;
+ ImGui::CheckboxFlags("NoCursors", (unsigned int*)&flags, ImPlotDragToolFlags_NoCursors); ImGui::SameLine();
+ ImGui::CheckboxFlags("NoFit", (unsigned int*)&flags, ImPlotDragToolFlags_NoFit); ImGui::SameLine();
+ ImGui::CheckboxFlags("NoInput", (unsigned int*)&flags, ImPlotDragToolFlags_NoInputs);
+ ImPlotAxisFlags ax_flags = ImPlotAxisFlags_NoTickLabels | ImPlotAxisFlags_NoTickMarks;
+ if (ImPlot::BeginPlot("##Bezier",ImVec2(-1,0),ImPlotFlags_CanvasOnly)) {
+ ImPlot::SetupAxes(0,0,ax_flags,ax_flags);
+ ImPlot::SetupAxesLimits(0,1,0,1);
+ static ImPlotPoint P[] = {ImPlotPoint(.05f,.05f), ImPlotPoint(0.2,0.4), ImPlotPoint(0.8,0.6), ImPlotPoint(.95f,.95f)};
+
+ ImPlot::DragPoint(0,&P[0].x,&P[0].y, ImVec4(0,0.9f,0,1),4,flags);
+ ImPlot::DragPoint(1,&P[1].x,&P[1].y, ImVec4(1,0.5f,1,1),4,flags);
+ ImPlot::DragPoint(2,&P[2].x,&P[2].y, ImVec4(0,0.5f,1,1),4,flags);
+ ImPlot::DragPoint(3,&P[3].x,&P[3].y, ImVec4(0,0.9f,0,1),4,flags);
+
+ static ImPlotPoint B[100];
+ for (int i = 0; i < 100; ++i) {
+ double t = i / 99.0;
+ double u = 1 - t;
+ double w1 = u*u*u;
+ double w2 = 3*u*u*t;
+ double w3 = 3*u*t*t;
+ double w4 = t*t*t;
+ B[i] = ImPlotPoint(w1*P[0].x + w2*P[1].x + w3*P[2].x + w4*P[3].x, w1*P[0].y + w2*P[1].y + w3*P[2].y + w4*P[3].y);
}
- ImPlot::SetNextPlotLimits(view.X.Min, view.X.Max, view.Y.Min, view.Y.Max, ImGuiCond_Always);
- if (ImPlot::BeginPlot("##View2",NULL,NULL,ImVec2(-1,150), ImPlotFlags_CanvasOnly, ImPlotAxisFlags_NoDecorations, ImPlotAxisFlags_NoDecorations)) {
- if (is_viewed) {
- ImPlot::PlotLine("Signal 1", x_data, y_data1, 512);
- ImPlot::PlotLine("Signal 2", x_data, y_data2, 512);
- ImPlot::PlotLine("Signal 3", x_data, y_data3, 512);
- }
- ImPlot::EndPlot();
+
+
+ ImPlot::SetNextLineStyle(ImVec4(1,0.5f,1,1));
+ ImPlot::PlotLine("##h1",&P[0].x, &P[0].y, 2, 0, sizeof(ImPlotPoint));
+ ImPlot::SetNextLineStyle(ImVec4(0,0.5f,1,1));
+ ImPlot::PlotLine("##h2",&P[2].x, &P[2].y, 2, 0, sizeof(ImPlotPoint));
+ ImPlot::SetNextLineStyle(ImVec4(0,0.9f,0,1), 2);
+ ImPlot::PlotLine("##bez",&B[0].x, &B[0].y, 100, 0, sizeof(ImPlotPoint));
+
+ ImPlot::EndPlot();
+ }
+}
+
+void ShowDemo_DragLines() {
+ ImGui::BulletText("Click and drag the horizontal and vertical lines.");
+ static double x1 = 0.2;
+ static double x2 = 0.8;
+ static double y1 = 0.25;
+ static double y2 = 0.75;
+ static double f = 0.1;
+ static ImPlotDragToolFlags flags = ImPlotDragToolFlags_None;
+ ImGui::CheckboxFlags("NoCursors", (unsigned int*)&flags, ImPlotDragToolFlags_NoCursors); ImGui::SameLine();
+ ImGui::CheckboxFlags("NoFit", (unsigned int*)&flags, ImPlotDragToolFlags_NoFit); ImGui::SameLine();
+ ImGui::CheckboxFlags("NoInput", (unsigned int*)&flags, ImPlotDragToolFlags_NoInputs);
+ if (ImPlot::BeginPlot("##lines",ImVec2(-1,0))) {
+ ImPlot::SetupAxesLimits(0,1,0,1);
+ ImPlot::DragLineX(0,&x1,ImVec4(1,1,1,1),1,flags);
+ ImPlot::DragLineX(1,&x2,ImVec4(1,1,1,1),1,flags);
+ ImPlot::DragLineY(2,&y1,ImVec4(1,1,1,1),1,flags);
+ ImPlot::DragLineY(3,&y2,ImVec4(1,1,1,1),1,flags);
+ double xs[1000], ys[1000];
+ for (int i = 0; i < 1000; ++i) {
+ xs[i] = (x2+x1)/2+fabs(x2-x1)*(i/1000.0f - 0.5f);
+ ys[i] = (y1+y2)/2+fabs(y2-y1)/2*sin(f*i/10);
}
+ ImPlot::PlotLine("Interactive Data", xs, ys, 1000);
+ ImPlot::DragLineY(120482,&f,ImVec4(1,0.5f,1,1),1,flags);
+ ImPlot::EndPlot();
}
- //-------------------------------------------------------------------------
- if (ImGui::CollapsingHeader("Legend")) {
- static ImPlotLocation loc = ImPlotLocation_East;
- static bool h = false; static bool o = true;
- ImGui::CheckboxFlags("North", (unsigned int*)&loc, ImPlotLocation_North); ImGui::SameLine();
- ImGui::CheckboxFlags("South", (unsigned int*)&loc, ImPlotLocation_South); ImGui::SameLine();
- ImGui::CheckboxFlags("West", (unsigned int*)&loc, ImPlotLocation_West); ImGui::SameLine();
- ImGui::CheckboxFlags("East", (unsigned int*)&loc, ImPlotLocation_East); ImGui::SameLine();
- ImGui::Checkbox("Horizontal##2", &h); ImGui::SameLine();
- ImGui::Checkbox("Outside", &o);
+}
- ImGui::SliderFloat2("LegendPadding", (float*)&GetStyle().LegendPadding, 0.0f, 20.0f, "%.0f");
- ImGui::SliderFloat2("LegendInnerPadding", (float*)&GetStyle().LegendInnerPadding, 0.0f, 10.0f, "%.0f");
- ImGui::SliderFloat2("LegendSpacing", (float*)&GetStyle().LegendSpacing, 0.0f, 5.0f, "%.0f");
+void ShowDemo_DragRects() {
- if (ImPlot::BeginPlot("##Legend","x","y",ImVec2(-1,0))) {
- ImPlot::SetLegendLocation(loc, h ? ImPlotOrientation_Horizontal : ImPlotOrientation_Vertical, o);
- static MyImPlot::WaveData data1(0.001, 0.2, 2, 0.75);
- static MyImPlot::WaveData data2(0.001, 0.2, 4, 0.25);
- static MyImPlot::WaveData data3(0.001, 0.2, 6, 0.5);
- ImPlot::PlotLineG("Item 1", MyImPlot::SineWave, &data1, 1000); // "Item 1" added to legend
- ImPlot::PlotLineG("Item 2##IDText", MyImPlot::SawWave, &data2, 1000); // "Item 2" added to legend, text after ## used for ID only
- ImPlot::PlotLineG("##NotListed", MyImPlot::SawWave, &data3, 1000); // plotted, but not added to legend
- ImPlot::PlotLineG("Item 3", MyImPlot::SineWave, &data1, 1000); // "Item 3" added to legend
- ImPlot::PlotLineG("Item 3", MyImPlot::SawWave, &data2, 1000); // combined with previous "Item 3"
- ImPlot::EndPlot();
+ static float x_data[512];
+ static float y_data1[512];
+ static float y_data2[512];
+ static float y_data3[512];
+ static float sampling_freq = 44100;
+ static float freq = 500;
+ for (size_t i = 0; i < 512; ++i) {
+ const float t = i / sampling_freq;
+ x_data[i] = t;
+ const float arg = 2 * 3.14f * freq * t;
+ y_data1[i] = sinf(arg);
+ y_data2[i] = y_data1[i] * -0.6f + sinf(2 * arg) * 0.4f;
+ y_data3[i] = y_data2[i] * -0.6f + sinf(3 * arg) * 0.4f;
+ }
+ ImGui::BulletText("Click and drag the edges, corners, and center of the rect.");
+ static ImPlotRect rect(0.0025,0.0045,0,0.5);
+ static ImPlotDragToolFlags flags = ImPlotDragToolFlags_None;
+ ImGui::CheckboxFlags("NoCursors", (unsigned int*)&flags, ImPlotDragToolFlags_NoCursors); ImGui::SameLine();
+ ImGui::CheckboxFlags("NoFit", (unsigned int*)&flags, ImPlotDragToolFlags_NoFit); ImGui::SameLine();
+ ImGui::CheckboxFlags("NoInput", (unsigned int*)&flags, ImPlotDragToolFlags_NoInputs);
+
+ if (ImPlot::BeginPlot("##Main",ImVec2(-1,150))) {
+ ImPlot::SetupAxes(NULL,NULL,ImPlotAxisFlags_NoTickLabels,ImPlotAxisFlags_NoTickLabels);
+ ImPlot::SetupAxesLimits(0,0.01,-1,1);
+ ImPlot::PlotLine("Signal 1", x_data, y_data1, 512);
+ ImPlot::PlotLine("Signal 2", x_data, y_data2, 512);
+ ImPlot::PlotLine("Signal 3", x_data, y_data3, 512);
+ ImPlot::DragRect(0,&rect.X.Min,&rect.Y.Min,&rect.X.Max,&rect.Y.Max,ImVec4(1,0,1,1),flags);
+ ImPlot::EndPlot();
+ }
+ if (ImPlot::BeginPlot("##rect",ImVec2(-1,150), ImPlotFlags_CanvasOnly)) {
+ ImPlot::SetupAxes(NULL,NULL,ImPlotAxisFlags_NoDecorations,ImPlotAxisFlags_NoDecorations);
+ ImPlot::SetupAxesLimits(rect.X.Min, rect.X.Max, rect.Y.Min, rect.Y.Max, ImGuiCond_Always);
+ ImPlot::PlotLine("Signal 1", x_data, y_data1, 512);
+ ImPlot::PlotLine("Signal 2", x_data, y_data2, 512);
+ ImPlot::PlotLine("Signal 3", x_data, y_data3, 512);
+ ImPlot::EndPlot();
+ }
+}
+
+ImPlotPoint FindCentroid(const ImVector<ImPlotPoint>& data, ImPlotRect& bounds, int& cnt) {
+ cnt = 0;
+ ImPlotPoint avg;
+ for (int i = 0; i < data.size(); ++i) {
+ if (bounds.Contains(data[i].x, data[i].y)) {
+ avg.x += data[i].x;
+ avg.y += data[i].y;
+ cnt++;
}
}
- //-------------------------------------------------------------------------
- if (ImGui::CollapsingHeader("Drag Lines and Points")) {
- ImGui::BulletText("Click and drag the horizontal and vertical lines.");
- static double x1 = 0.2;
- static double x2 = 0.8;
- static double y1 = 0.25;
- static double y2 = 0.75;
- static double f = 0.1;
- static bool show_labels = true;
- ImGui::Checkbox("Show Labels##1",&show_labels);
- ImPlot::SetNextPlotLimits(0,1,0,1);
- if (ImPlot::BeginPlot("##guides",0,0,ImVec2(-1,0),ImPlotFlags_YAxis2)) {
- ImPlot::DragLineX("x1",&x1,show_labels);
- ImPlot::DragLineX("x2",&x2,show_labels);
- ImPlot::DragLineY("y1",&y1,show_labels);
- ImPlot::DragLineY("y2",&y2,show_labels);
- double xs[1000], ys[1000];
- for (int i = 0; i < 1000; ++i) {
- xs[i] = (x2+x1)/2+fabs(x2-x1)*(i/1000.0f - 0.5f);
- ys[i] = (y1+y2)/2+fabs(y2-y1)/2*sin(f*i/10);
+ if (cnt > 0) {
+ avg.x = avg.x / cnt;
+ avg.y = avg.y / cnt;
+ }
+ return avg;
+}
+
+void ShowDemo_Querying() {
+ static ImVector<ImPlotPoint> data;
+ static ImVector<ImPlotRect> rects;
+ static ImPlotRect limits, select;
+ static bool init = true;
+ if (init) {
+ for (int i = 0; i < 50; ++i)
+ {
+ double x = RandomRange(0.1, 0.9);
+ double y = RandomRange(0.1, 0.9);
+ data.push_back(ImPlotPoint(x,y));
+ }
+ init = false;
+ }
+
+ ImGui::BulletText("Box select and left click mouse to create a new query rect.");
+ ImGui::BulletText("Ctrl + click in the plot area to draw points.");
+
+ if (ImGui::Button("Clear Queries"))
+ rects.shrink(0);
+
+ if (ImPlot::BeginPlot("##Centroid")) {
+ ImPlot::SetupAxesLimits(0,1,0,1);
+ if (ImPlot::IsPlotHovered() && ImGui::IsMouseClicked(0) && ImGui::GetIO().KeyCtrl) {
+ ImPlotPoint pt = ImPlot::GetPlotMousePos();
+ data.push_back(pt);
+ }
+ ImPlot::PlotScatter("Points", &data[0].x, &data[0].y, data.size(), 0, 2 * sizeof(double));
+ if (ImPlot::IsPlotSelected()) {
+ select = ImPlot::GetPlotSelection();
+ int cnt;
+ ImPlotPoint centroid = FindCentroid(data,select,cnt);
+ if (cnt > 0) {
+ ImPlot::SetNextMarkerStyle(ImPlotMarker_Square,6);
+ ImPlot::PlotScatter("Centroid", &centroid.x, &centroid.y, 1);
+ }
+ if (ImGui::IsMouseClicked(ImPlot::GetInputMap().SelectCancel)) {
+ CancelPlotSelection();
+ rects.push_back(select);
}
- ImPlot::PlotLine("Interactive Data", xs, ys, 1000);
- ImPlot::SetPlotYAxis(ImPlotYAxis_2);
- ImPlot::DragLineY("f",&f,show_labels,ImVec4(1,0.5f,1,1));
- ImPlot::EndPlot();
}
- ImGui::BulletText("Click and drag any point.");
- ImGui::Checkbox("Show Labels##2",&show_labels);
- ImPlotAxisFlags flags = ImPlotAxisFlags_NoTickLabels | ImPlotAxisFlags_NoTickMarks;
- ImPlot::SetNextPlotLimits(0,1,0,1);
- if (ImPlot::BeginPlot("##Bezier",0,0,ImVec2(-1,0),ImPlotFlags_CanvasOnly,flags,flags)) {
- static ImPlotPoint P[] = {ImPlotPoint(.05f,.05f), ImPlotPoint(0.2,0.4), ImPlotPoint(0.8,0.6), ImPlotPoint(.95f,.95f)};
- static ImPlotPoint B[100];
- for (int i = 0; i < 100; ++i) {
- double t = i / 99.0;
- double u = 1 - t;
- double w1 = u*u*u;
- double w2 = 3*u*u*t;
- double w3 = 3*u*t*t;
- double w4 = t*t*t;
- B[i] = ImPlotPoint(w1*P[0].x + w2*P[1].x + w3*P[2].x + w4*P[3].x, w1*P[0].y + w2*P[1].y + w3*P[2].y + w4*P[3].y);
+ for (int i = 0; i < rects.size(); ++i) {
+ int cnt;
+ ImPlotPoint centroid = FindCentroid(data,rects[i],cnt);
+ if (cnt > 0) {
+ ImPlot::SetNextMarkerStyle(ImPlotMarker_Square,6);
+ ImPlot::PlotScatter("Centroid", &centroid.x, &centroid.y, 1);
}
- ImPlot::SetNextLineStyle(ImVec4(0,0.9f,0,1), 2);
- ImPlot::PlotLine("##bez",&B[0].x, &B[0].y, 100, 0, sizeof(ImPlotPoint));
- ImPlot::SetNextLineStyle(ImVec4(1,0.5f,1,1));
- ImPlot::PlotLine("##h1",&P[0].x, &P[0].y, 2, 0, sizeof(ImPlotPoint));
- ImPlot::SetNextLineStyle(ImVec4(0,0.5f,1,1));
- ImPlot::PlotLine("##h2",&P[2].x, &P[2].y, 2, 0, sizeof(ImPlotPoint));
- ImPlot::DragPoint("P0",&P[0].x,&P[0].y, show_labels, ImVec4(0,0.9f,0,1));
- ImPlot::DragPoint("P1",&P[1].x,&P[1].y, show_labels, ImVec4(1,0.5f,1,1));
- ImPlot::DragPoint("P2",&P[2].x,&P[2].y, show_labels, ImVec4(0,0.5f,1,1));
- ImPlot::DragPoint("P3",&P[3].x,&P[3].y, show_labels, ImVec4(0,0.9f,0,1));
- ImPlot::EndPlot();
+ ImPlot::DragRect(i,&rects[i].X.Min,&rects[i].Y.Min,&rects[i].X.Max,&rects[i].Y.Max,ImVec4(1,0,1,1));
}
+ limits = ImPlot::GetPlotLimits();
+ ImPlot::EndPlot();
}
- if (ImGui::CollapsingHeader("Annotations")) {
- static bool clamp = false;
- ImGui::Checkbox("Clamp",&clamp);
- ImPlot::SetNextPlotLimits(0,2,0,1);
- if (ImPlot::BeginPlot("##Annotations")) {
+}
- static float p[] = {0.25f, 0.25f, 0.75f, 0.75f, 0.25f};
- ImPlot::PlotScatter("##Points",&p[0],&p[1],4);
- ImVec4 col = GetLastItemColor();
- clamp ? ImPlot::AnnotateClamped(0.25,0.25,ImVec2(-15,15),col,"BL") : ImPlot::Annotate(0.25,0.25,ImVec2(-15,15),col,"BL");
- clamp ? ImPlot::AnnotateClamped(0.75,0.25,ImVec2(15,15),col,"BR") : ImPlot::Annotate(0.75,0.25,ImVec2(15,15),col,"BR");
- clamp ? ImPlot::AnnotateClamped(0.75,0.75,ImVec2(15,-15),col,"TR") : ImPlot::Annotate(0.75,0.75,ImVec2(15,-15),col,"TR");
- clamp ? ImPlot::AnnotateClamped(0.25,0.75,ImVec2(-15,-15),col,"TL") : ImPlot::Annotate(0.25,0.75,ImVec2(-15,-15),col,"TL");
- clamp ? ImPlot::AnnotateClamped(0.5,0.5,ImVec2(0,0),col,"Center") : ImPlot::Annotate(0.5,0.5,ImVec2(0,0),col,"Center");
+void ShowDemo_Annotations() {
+ static bool clamp = false;
+ ImGui::Checkbox("Clamp",&clamp);
+ if (ImPlot::BeginPlot("##Annotations")) {
+ ImPlot::SetupAxesLimits(0,2,0,1);
+ static float p[] = {0.25f, 0.25f, 0.75f, 0.75f, 0.25f};
+ ImPlot::PlotScatter("##Points",&p[0],&p[1],4);
+ ImVec4 col = GetLastItemColor();
+ ImPlot::Annotation(0.25,0.25,col,ImVec2(-15,15),clamp,"BL");
+ ImPlot::Annotation(0.75,0.25,col,ImVec2(15,15),clamp,"BR");
+ ImPlot::Annotation(0.75,0.75,col,ImVec2(15,-15),clamp,"TR");
+ ImPlot::Annotation(0.25,0.75,col,ImVec2(-15,-15),clamp,"TL");
+ ImPlot::Annotation(0.5,0.5,col,ImVec2(0,0),clamp,"Center");
- float bx[] = {1.2f,1.5f,1.8f};
- float by[] = {0.25f, 0.5f, 0.75f};
- ImPlot::PlotBars("##Bars",bx,by,3,0.2);
- for (int i = 0; i < 3; ++i)
- ImPlot::Annotate(bx[i],by[i],ImVec2(0,-5),"B[%d]=%.2f",i,by[i]);
- ImPlot::EndPlot();
+ ImPlot::Annotation(1.25,0.75,ImVec4(0,1,0,1),ImVec2(0,0),clamp);
+
+ float bx[] = {1.2f,1.5f,1.8f};
+ float by[] = {0.25f, 0.5f, 0.75f};
+ ImPlot::PlotBars("##Bars",bx,by,3,0.2);
+ for (int i = 0; i < 3; ++i)
+ ImPlot::Annotation(bx[i],by[i],ImVec4(0,0,0,0),ImVec2(0,-5),clamp,"B[%d]=%.2f",i,by[i]);
+ ImPlot::EndPlot();
+ }
+}
+
+void ShowDemo_Tags() {
+ static bool show = true;
+ ImGui::Checkbox("Show Tags",&show);
+ if (ImPlot::BeginPlot("##Tags")) {
+ ImPlot::SetupAxis(ImAxis_X2);
+ ImPlot::SetupAxis(ImAxis_Y2);
+ if (show) {
+ ImPlot::TagX(0.25, ImVec4(1,1,0,1));
+ ImPlot::TagY(0.75, ImVec4(1,1,0,1));
+ static double drag_tag = 0.25;
+ ImPlot::DragLineY(0,&drag_tag,ImVec4(1,0,0,1),1,ImPlotDragToolFlags_NoFit);
+ ImPlot::TagY(drag_tag, ImVec4(1,0,0,1), "Drag");
+ SetAxes(ImAxis_X2, ImAxis_Y2);
+ ImPlot::TagX(0.5, ImVec4(0,1,1,1), "%s", "MyTag");
+ ImPlot::TagY(0.5, ImVec4(0,1,1,1), "Tag: %d", 42);
}
+ ImPlot::EndPlot();
}
- //-------------------------------------------------------------------------
- if (ImGui::CollapsingHeader("Drag and Drop")) {
- ImGui::BulletText("Drag/drop items from the left column.");
- ImGui::BulletText("Drag/drop items between plots.");
- ImGui::Indent();
- ImGui::BulletText("Plot 1 Targets: Plot, Y-Axes, Legend");
- ImGui::BulletText("Plot 1 Sources: Legend Items");
- ImGui::BulletText("Plot 2 Targets: Plot, X-Axis, Y-Axis");
- ImGui::BulletText("Plot 2 Sources: Plot, X-Axis, Y-Axis (hold Ctrl)");
- ImGui::Unindent();
+}
- // convenience struct to manage DND items; do this however you like
- struct MyDndItem {
- int Idx;
- int Plt;
- int Yax;
- char Label[16];
- ImVector<ImVec2> Data;
- ImVec4 Color;
- MyDndItem() {
- static int i = 0;
- Idx = i++;
- Plt = 0;
- Yax = ImPlotYAxis_1;
- sprintf(Label, "%02d Hz", Idx+1);
- Color = RandomColor();
- Data.reserve(1001);
- for (int k = 0; k < 1001; ++k) {
- float t = k * 1.0f / 999;
- Data.push_back(ImVec2(t, 0.5f + 0.5f * sinf(2*3.14f*t*(Idx+1))));
- }
+void ShowDemo_DragAndDrop() {
+ ImGui::BulletText("Drag/drop items from the left column.");
+ ImGui::BulletText("Drag/drop items between plots.");
+ ImGui::Indent();
+ ImGui::BulletText("Plot 1 Targets: Plot, Y-Axes, Legend");
+ ImGui::BulletText("Plot 1 Sources: Legend Item Labels");
+ ImGui::BulletText("Plot 2 Targets: Plot, X-Axis, Y-Axis");
+ ImGui::BulletText("Plot 2 Sources: Plot, X-Axis, Y-Axis (hold Ctrl)");
+ ImGui::Unindent();
+
+ // convenience struct to manage DND items; do this however you like
+ struct MyDndItem {
+ int Idx;
+ int Plt;
+ ImAxis Yax;
+ char Label[16];
+ ImVector<ImVec2> Data;
+ ImVec4 Color;
+ MyDndItem() {
+ static int i = 0;
+ Idx = i++;
+ Plt = 0;
+ Yax = ImAxis_Y1;
+ sprintf(Label, "%02d Hz", Idx+1);
+ Color = RandomColor();
+ Data.reserve(1001);
+ for (int k = 0; k < 1001; ++k) {
+ float t = k * 1.0f / 999;
+ Data.push_back(ImVec2(t, 0.5f + 0.5f * sinf(2*3.14f*t*(Idx+1))));
}
- void Reset() { Plt = 0; Yax = ImPlotYAxis_1; }
- };
+ }
+ void Reset() { Plt = 0; Yax = ImAxis_Y1; }
+ };
- const int k_dnd = 20;
- static MyDndItem dnd[k_dnd];
- static MyDndItem* dndx = NULL; // for plot 2
- static MyDndItem* dndy = NULL; // for plot 2
+ const int k_dnd = 20;
+ static MyDndItem dnd[k_dnd];
+ static MyDndItem* dndx = NULL; // for plot 2
+ static MyDndItem* dndy = NULL; // for plot 2
- // child window to serve as initial source for our DND items
- ImGui::BeginChild("DND_LEFT",ImVec2(100,400));
- if (ImGui::Button("Reset Data", ImVec2(100, 0))) {
- for (int k = 0; k < k_dnd; ++k)
- dnd[k].Reset();
- dndx = dndy = NULL;
- }
- for (int k = 0; k < k_dnd; ++k) {
- if (dnd[k].Plt > 0)
- continue;
+ // child window to serve as initial source for our DND items
+ ImGui::BeginChild("DND_LEFT",ImVec2(100,400));
+ if (ImGui::Button("Reset Data")) {
+ for (int k = 0; k < k_dnd; ++k)
+ dnd[k].Reset();
+ dndx = dndy = NULL;
+ }
+ for (int k = 0; k < k_dnd; ++k) {
+ if (dnd[k].Plt > 0)
+ continue;
+ ImPlot::ItemIcon(dnd[k].Color); ImGui::SameLine();
+ ImGui::Selectable(dnd[k].Label, false, 0, ImVec2(100, 0));
+ if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) {
+ ImGui::SetDragDropPayload("MY_DND", &k, sizeof(int));
ImPlot::ItemIcon(dnd[k].Color); ImGui::SameLine();
- ImGui::Selectable(dnd[k].Label, false, 0, ImVec2(100, 0));
- if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) {
- ImGui::SetDragDropPayload("MY_DND", &k, sizeof(int));
- ImPlot::ItemIcon(dnd[k].Color); ImGui::SameLine();
- ImGui::TextUnformatted(dnd[k].Label);
- ImGui::EndDragDropSource();
- }
+ ImGui::TextUnformatted(dnd[k].Label);
+ ImGui::EndDragDropSource();
}
- ImGui::EndChild();
- if (ImGui::BeginDragDropTarget()) {
- if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("MY_DND")) {
- int i = *(int*)payload->Data; dnd[i].Reset();
- }
- ImGui::EndDragDropTarget();
+ }
+ ImGui::EndChild();
+ if (ImGui::BeginDragDropTarget()) {
+ if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("MY_DND")) {
+ int i = *(int*)payload->Data; dnd[i].Reset();
}
+ ImGui::EndDragDropTarget();
+ }
- ImGui::SameLine();
- ImGui::BeginChild("DND_RIGHT",ImVec2(-1,400));
- // plot 1 (time series)
- ImPlotAxisFlags flags = ImPlotAxisFlags_NoTickLabels | ImPlotAxisFlags_NoGridLines;
- if (ImPlot::BeginPlot("##DND1", NULL, "[drop here]", ImVec2(-1,195), ImPlotFlags_YAxis2 | ImPlotFlags_YAxis3, flags | ImPlotAxisFlags_Lock, flags, flags, flags, "[drop here]", "[drop here]")) {
- for (int k = 0; k < k_dnd; ++k) {
- if (dnd[k].Plt == 1 && dnd[k].Data.size() > 0) {
- ImPlot::SetPlotYAxis(dnd[k].Yax);
- ImPlot::SetNextLineStyle(dnd[k].Color);
- static char label[32];
- sprintf(label,"%s (Y%d)", dnd[k].Label, dnd[k].Yax+1);
- ImPlot::PlotLine(label, &dnd[k].Data[0].x, &dnd[k].Data[0].y, dnd[k].Data.size(), 0, 2 * sizeof(float));
- // allow legend item labels to be DND sources
- if (ImPlot::BeginDragDropSourceItem(label)) {
- ImGui::SetDragDropPayload("MY_DND", &k, sizeof(int));
- ImPlot::ItemIcon(dnd[k].Color); ImGui::SameLine();
- ImGui::TextUnformatted(dnd[k].Label);
- ImPlot::EndDragDropSource();
- }
- }
- }
- // allow the main plot area to be a DND target
- if (ImPlot::BeginDragDropTarget()) {
- if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("MY_DND")) {
- int i = *(int*)payload->Data; dnd[i].Plt = 1; dnd[i].Yax = 0;
- }
- ImPlot::EndDragDropTarget();
- }
- // allow each y-axis to be a DND target
- for (int y = 0; y < 3; ++y) {
- if (ImPlot::BeginDragDropTargetY(y)) {
- if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("MY_DND")) {
- int i = *(int*)payload->Data; dnd[i].Plt = 1; dnd[i].Yax = y;
- }
- ImPlot::EndDragDropTarget();
+ ImGui::SameLine();
+ ImGui::BeginChild("DND_RIGHT",ImVec2(-1,400));
+ // plot 1 (time series)
+ ImPlotAxisFlags flags = ImPlotAxisFlags_NoTickLabels | ImPlotAxisFlags_NoGridLines;
+ if (ImPlot::BeginPlot("##DND1", ImVec2(-1,195))) {
+ ImPlot::SetupAxis(ImAxis_X1, NULL, flags|ImPlotAxisFlags_Lock);
+ ImPlot::SetupAxis(ImAxis_Y1, "[drop here]", flags);
+ ImPlot::SetupAxis(ImAxis_Y2, "[drop here]", flags|ImPlotAxisFlags_Opposite);
+ ImPlot::SetupAxis(ImAxis_Y3, "[drop here]", flags|ImPlotAxisFlags_Opposite);
+
+ for (int k = 0; k < k_dnd; ++k) {
+ if (dnd[k].Plt == 1 && dnd[k].Data.size() > 0) {
+ ImPlot::SetAxis(dnd[k].Yax);
+ ImPlot::SetNextLineStyle(dnd[k].Color);
+ ImPlot::PlotLine(dnd[k].Label, &dnd[k].Data[0].x, &dnd[k].Data[0].y, dnd[k].Data.size(), 0, 2 * sizeof(float));
+ // allow legend item labels to be DND sources
+ if (ImPlot::BeginDragDropSourceItem(dnd[k].Label)) {
+ ImGui::SetDragDropPayload("MY_DND", &k, sizeof(int));
+ ImPlot::ItemIcon(dnd[k].Color); ImGui::SameLine();
+ ImGui::TextUnformatted(dnd[k].Label);
+ ImPlot::EndDragDropSource();
}
}
- // allow the legend to be a DND target
- if (ImPlot::BeginDragDropTargetLegend()) {
- if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("MY_DND")) {
- int i = *(int*)payload->Data; dnd[i].Plt = 1; dnd[i].Yax = 0;
- }
- ImPlot::EndDragDropTarget();
- }
- ImPlot::EndPlot();
}
- // plot 2 (Lissajous)
- ImPlot::PushStyleColor(ImPlotCol_XAxis, dndx == NULL ? ImPlot::GetStyle().Colors[ImPlotCol_XAxis] : dndx->Color);
- ImPlot::PushStyleColor(ImPlotCol_YAxis, dndy == NULL ? ImPlot::GetStyle().Colors[ImPlotCol_YAxis] : dndy->Color);
- if (ImPlot::BeginPlot("##DND2", dndx == NULL ? "[drop here]" : dndx->Label, dndy == NULL ? "[drop here]" : dndy->Label, ImVec2(-1,195), 0, flags, flags )) {
- if (dndx != NULL && dndy != NULL) {
- ImVec4 mixed((dndx->Color.x + dndy->Color.x)/2,(dndx->Color.y + dndy->Color.y)/2,(dndx->Color.z + dndy->Color.z)/2,(dndx->Color.w + dndy->Color.w)/2);
- ImPlot::SetNextLineStyle(mixed);
- ImPlot::PlotLine("##dndxy", &dndx->Data[0].y, &dndy->Data[0].y, dndx->Data.size(), 0, 2 * sizeof(float));
+ // allow the main plot area to be a DND target
+ if (ImPlot::BeginDragDropTargetPlot()) {
+ if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("MY_DND")) {
+ int i = *(int*)payload->Data; dnd[i].Plt = 1; dnd[i].Yax = ImAxis_Y1;
}
- // allow the x-axis to be a DND target
- if (ImPlot::BeginDragDropTargetX()) {
+ ImPlot::EndDragDropTarget();
+ }
+ // allow each y-axis to be a DND target
+ for (int y = ImAxis_Y1; y <= ImAxis_Y3; ++y) {
+ if (ImPlot::BeginDragDropTargetAxis(y)) {
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("MY_DND")) {
- int i = *(int*)payload->Data; dndx = &dnd[i];
+ int i = *(int*)payload->Data; dnd[i].Plt = 1; dnd[i].Yax = y;
}
ImPlot::EndDragDropTarget();
}
- // allow the x-axis to be a DND source
- if (dndx != NULL && ImPlot::BeginDragDropSourceX()) {
- ImGui::SetDragDropPayload("MY_DND", &dndx->Idx, sizeof(int));
- ImPlot::ItemIcon(dndx->Color); ImGui::SameLine();
- ImGui::TextUnformatted(dndx->Label);
- ImPlot::EndDragDropSource();
- }
- // allow the y-axis to be a DND target
- if (ImPlot::BeginDragDropTargetY()) {
- if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("MY_DND")) {
- int i = *(int*)payload->Data; dndy = &dnd[i];
- }
- ImPlot::EndDragDropTarget();
+ }
+ // allow the legend to be a DND target
+ if (ImPlot::BeginDragDropTargetLegend()) {
+ if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("MY_DND")) {
+ int i = *(int*)payload->Data; dnd[i].Plt = 1; dnd[i].Yax = ImAxis_Y1;
}
- // allow the y-axis to be a DND source
- if (dndy != NULL && ImPlot::BeginDragDropSourceY()) {
- ImGui::SetDragDropPayload("MY_DND", &dndy->Idx, sizeof(int));
- ImPlot::ItemIcon(dndy->Color); ImGui::SameLine();
- ImGui::TextUnformatted(dndy->Label);
- ImPlot::EndDragDropSource();
+ ImPlot::EndDragDropTarget();
+ }
+ ImPlot::EndPlot();
+ }
+ // plot 2 (Lissajous)
+ if (ImPlot::BeginPlot("##DND2", ImVec2(-1,195))) {
+ ImPlot::PushStyleColor(ImPlotCol_AxisBg, dndx != NULL ? dndx->Color : ImPlot::GetStyle().Colors[ImPlotCol_AxisBg]);
+ ImPlot::SetupAxis(ImAxis_X1, dndx == NULL ? "[drop here]" : dndx->Label, flags);
+ ImPlot::PushStyleColor(ImPlotCol_AxisBg, dndy != NULL ? dndy->Color : ImPlot::GetStyle().Colors[ImPlotCol_AxisBg]);
+ ImPlot::SetupAxis(ImAxis_Y1, dndy == NULL ? "[drop here]" : dndy->Label, flags);
+ ImPlot::PopStyleColor(2);
+ if (dndx != NULL && dndy != NULL) {
+ ImVec4 mixed((dndx->Color.x + dndy->Color.x)/2,(dndx->Color.y + dndy->Color.y)/2,(dndx->Color.z + dndy->Color.z)/2,(dndx->Color.w + dndy->Color.w)/2);
+ ImPlot::SetNextLineStyle(mixed);
+ ImPlot::PlotLine("##dndxy", &dndx->Data[0].y, &dndy->Data[0].y, dndx->Data.size(), 0, 2 * sizeof(float));
+ }
+ // allow the x-axis to be a DND target
+ if (ImPlot::BeginDragDropTargetAxis(ImAxis_X1)) {
+ if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("MY_DND")) {
+ int i = *(int*)payload->Data; dndx = &dnd[i];
}
- // allow the plot area to be a DND target
- if (ImPlot::BeginDragDropTarget()) {
- if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("MY_DND")) {
- int i = *(int*)payload->Data; dndx = dndy = &dnd[i];
- }
+ ImPlot::EndDragDropTarget();
+ }
+ // allow the x-axis to be a DND source
+ if (dndx != NULL && ImPlot::BeginDragDropSourceAxis(ImAxis_X1)) {
+ ImGui::SetDragDropPayload("MY_DND", &dndx->Idx, sizeof(int));
+ ImPlot::ItemIcon(dndx->Color); ImGui::SameLine();
+ ImGui::TextUnformatted(dndx->Label);
+ ImPlot::EndDragDropSource();
+ }
+ // allow the y-axis to be a DND target
+ if (ImPlot::BeginDragDropTargetAxis(ImAxis_Y1)) {
+ if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("MY_DND")) {
+ int i = *(int*)payload->Data; dndy = &dnd[i];
}
- // allow the plot area to be a DND source
- if (ImPlot::BeginDragDropSource()) {
- ImGui::TextUnformatted("Yes, you can\ndrag this!");
- ImPlot::EndDragDropSource();
+ ImPlot::EndDragDropTarget();
+ }
+ // allow the y-axis to be a DND source
+ if (dndy != NULL && ImPlot::BeginDragDropSourceAxis(ImAxis_Y1)) {
+ ImGui::SetDragDropPayload("MY_DND", &dndy->Idx, sizeof(int));
+ ImPlot::ItemIcon(dndy->Color); ImGui::SameLine();
+ ImGui::TextUnformatted(dndy->Label);
+ ImPlot::EndDragDropSource();
+ }
+ // allow the plot area to be a DND target
+ if (ImPlot::BeginDragDropTargetPlot()) {
+ if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("MY_DND")) {
+ int i = *(int*)payload->Data; dndx = dndy = &dnd[i];
}
- ImPlot::EndPlot();
}
- ImPlot::PopStyleColor(2);
- ImGui::EndChild();
+ // allow the plot area to be a DND source
+ if (ImPlot::BeginDragDropSourcePlot()) {
+ ImGui::TextUnformatted("Yes, you can\ndrag this!");
+ ImPlot::EndDragDropSource();
+ }
+ ImPlot::EndPlot();
}
- //-------------------------------------------------------------------------
- if (ImGui::CollapsingHeader("Tables")) {
+ ImGui::EndChild();
+}
+
+void ShowDemo_Tables() {
#ifdef IMGUI_HAS_TABLE
- static ImGuiTableFlags flags = ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_RowBg;
- static bool anim = true;
- static int offset = 0;
- ImGui::BulletText("Plots can be used inside of ImGui tables.");
- ImGui::Checkbox("Animate",&anim);
- if (anim)
- offset = (offset + 1) % 100;
- if (ImGui::BeginTable("##table", 3, flags, ImVec2(-1,0))) {
- ImGui::TableSetupColumn("Electrode", ImGuiTableColumnFlags_WidthFixed, 75.0f);
- ImGui::TableSetupColumn("Voltage", ImGuiTableColumnFlags_WidthFixed, 75.0f);
- ImGui::TableSetupColumn("EMG Signal");
- ImGui::TableHeadersRow();
- ImPlot::PushColormap(ImPlotColormap_Cool);
- for (int row = 0; row < 10; row++) {
- ImGui::TableNextRow();
- static float data[100];
- srand(row);
- for (int i = 0; i < 100; ++i)
- data[i] = RandomRange(0.0f,10.0f);
- ImGui::TableSetColumnIndex(0);
- ImGui::Text("EMG %d", row);
- ImGui::TableSetColumnIndex(1);
- ImGui::Text("%.3f V", data[offset]);
- ImGui::TableSetColumnIndex(2);
- ImGui::PushID(row);
- MyImPlot::Sparkline("##spark",data,100,0,11.0f,offset,ImPlot::GetColormapColor(row),ImVec2(-1, 35));
- ImGui::PopID();
- }
- ImPlot::PopColormap();
- ImGui::EndTable();
+ static ImGuiTableFlags flags = ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV |
+ ImGuiTableFlags_RowBg | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable;
+ static bool anim = true;
+ static int offset = 0;
+ ImGui::BulletText("Plots can be used inside of ImGui tables as another means of creating subplots.");
+ ImGui::Checkbox("Animate",&anim);
+ if (anim)
+ offset = (offset + 1) % 100;
+ if (ImGui::BeginTable("##table", 3, flags, ImVec2(-1,0))) {
+ ImGui::TableSetupColumn("Electrode", ImGuiTableColumnFlags_WidthFixed, 75.0f);
+ ImGui::TableSetupColumn("Voltage", ImGuiTableColumnFlags_WidthFixed, 75.0f);
+ ImGui::TableSetupColumn("EMG Signal");
+ ImGui::TableHeadersRow();
+ ImPlot::PushColormap(ImPlotColormap_Cool);
+ for (int row = 0; row < 10; row++) {
+ ImGui::TableNextRow();
+ static float data[100];
+ srand(row);
+ for (int i = 0; i < 100; ++i)
+ data[i] = RandomRange(0.0f,10.0f);
+ ImGui::TableSetColumnIndex(0);
+ ImGui::Text("EMG %d", row);
+ ImGui::TableSetColumnIndex(1);
+ ImGui::Text("%.3f V", data[offset]);
+ ImGui::TableSetColumnIndex(2);
+ ImGui::PushID(row);
+ MyImPlot::Sparkline("##spark",data,100,0,11.0f,offset,ImPlot::GetColormapColor(row),ImVec2(-1, 35));
+ ImGui::PopID();
}
+ ImPlot::PopColormap();
+ ImGui::EndTable();
+ }
#else
ImGui::BulletText("You need to merge the ImGui 'tables' branch for this section.");
#endif
- }
- //-------------------------------------------------------------------------
- if (ImGui::CollapsingHeader("Offset and Stride")) {
- static const int k_circles = 11;
- static const int k_points_per = 50;
- static const int k_size = 2 * k_points_per * k_circles;
- static double interleaved_data[k_size];
- for (int p = 0; p < k_points_per; ++p) {
- for (int c = 0; c < k_circles; ++c) {
- double r = (double)c / (k_circles - 1) * 0.2 + 0.2;
- interleaved_data[p*2*k_circles + 2*c + 0] = 0.5 + r * cos((double)p/k_points_per * 6.28);
- interleaved_data[p*2*k_circles + 2*c + 1] = 0.5 + r * sin((double)p/k_points_per * 6.28);
- }
+}
+
+void ShowDemo_OffsetAndStride() {
+ static const int k_circles = 11;
+ static const int k_points_per = 50;
+ static const int k_size = 2 * k_points_per * k_circles;
+ static double interleaved_data[k_size];
+ for (int p = 0; p < k_points_per; ++p) {
+ for (int c = 0; c < k_circles; ++c) {
+ double r = (double)c / (k_circles - 1) * 0.2 + 0.2;
+ interleaved_data[p*2*k_circles + 2*c + 0] = 0.5 + r * cos((double)p/k_points_per * 6.28);
+ interleaved_data[p*2*k_circles + 2*c + 1] = 0.5 + r * sin((double)p/k_points_per * 6.28);
}
- static int offset = 0;
- ImGui::BulletText("Offsetting is useful for realtime plots (see above) and circular buffers.");
- ImGui::BulletText("Striding is useful for interleaved data (e.g. audio) or plotting structs.");
- ImGui::BulletText("Here, all circle data is stored in a single interleaved buffer:");
- ImGui::BulletText("[c0.x0 c0.y0 ... cn.x0 cn.y0 c0.x1 c0.y1 ... cn.x1 cn.y1 ... cn.xm cn.ym]");
- ImGui::BulletText("The offset value indicates which circle point index is considered the first.");
- ImGui::BulletText("Offsets can be negative and/or larger than the actual data count.");
- ImGui::SliderInt("Offset", &offset, -2*k_points_per, 2*k_points_per);
- if (ImPlot::BeginPlot("##strideoffset",0,0,ImVec2(-1,0), ImPlotFlags_Equal)) {
- ImPlot::PushColormap(ImPlotColormap_Jet);
- char buff[16];
- for (int c = 0; c < k_circles; ++c) {
- sprintf(buff, "Circle %d", c);
- ImPlot::PlotLine(buff, &interleaved_data[c*2 + 0], &interleaved_data[c*2 + 1], k_points_per, offset, 2*k_circles*sizeof(double));
- }
- ImPlot::EndPlot();
- ImPlot::PopColormap();
+ }
+ static int offset = 0;
+ ImGui::BulletText("Offsetting is useful for realtime plots (see above) and circular buffers.");
+ ImGui::BulletText("Striding is useful for interleaved data (e.g. audio) or plotting structs.");
+ ImGui::BulletText("Here, all circle data is stored in a single interleaved buffer:");
+ ImGui::BulletText("[c0.x0 c0.y0 ... cn.x0 cn.y0 c0.x1 c0.y1 ... cn.x1 cn.y1 ... cn.xm cn.ym]");
+ ImGui::BulletText("The offset value indicates which circle point index is considered the first.");
+ ImGui::BulletText("Offsets can be negative and/or larger than the actual data count.");
+ ImGui::SliderInt("Offset", &offset, -2*k_points_per, 2*k_points_per);
+ if (ImPlot::BeginPlot("##strideoffset",ImVec2(-1,0),ImPlotFlags_Equal)) {
+ ImPlot::PushColormap(ImPlotColormap_Jet);
+ char buff[16];
+ for (int c = 0; c < k_circles; ++c) {
+ sprintf(buff, "Circle %d", c);
+ ImPlot::PlotLine(buff, &interleaved_data[c*2 + 0], &interleaved_data[c*2 + 1], k_points_per, offset, 2*k_circles*sizeof(double));
}
- // offset++; uncomment for animation!
+ ImPlot::EndPlot();
+ ImPlot::PopColormap();
}
- //-------------------------------------------------------------------------
- if (ImGui::CollapsingHeader("Custom Data and Getters")) {
- ImGui::BulletText("You can plot custom structs using the stride feature.");
- ImGui::BulletText("Most plotters can also be passed a function pointer for getting data.");
- ImGui::Indent();
- ImGui::BulletText("You can optionally pass user data to be given to your getter function.");
- ImGui::BulletText("C++ lambdas can be passed as function pointers as well!");
- ImGui::Unindent();
+ // offset++; uncomment for animation!
+}
- MyImPlot::Vector2f vec2_data[2] = { MyImPlot::Vector2f(0,0), MyImPlot::Vector2f(1,1) };
+void ShowDemo_CustomDataAndGetters() {
+ ImGui::BulletText("You can plot custom structs using the stride feature.");
+ ImGui::BulletText("Most plotters can also be passed a function pointer for getting data.");
+ ImGui::Indent();
+ ImGui::BulletText("You can optionally pass user data to be given to your getter function.");
+ ImGui::BulletText("C++ lambdas can be passed as function pointers as well!");
+ ImGui::Unindent();
- if (ImPlot::BeginPlot("##Custom Data")) {
+ MyImPlot::Vector2f vec2_data[2] = { MyImPlot::Vector2f(0,0), MyImPlot::Vector2f(1,1) };
- // custom structs using stride example:
- ImPlot::PlotLine("Vector2f", &vec2_data[0].x, &vec2_data[0].y, 2, 0, sizeof(MyImPlot::Vector2f) /* or sizeof(float) * 2 */);
+ if (ImPlot::BeginPlot("##Custom Data")) {
- // custom getter example 1:
- ImPlot::PlotLineG("Spiral", MyImPlot::Spiral, NULL, 1000);
+ // custom structs using stride example:
+ ImPlot::PlotLine("Vector2f", &vec2_data[0].x, &vec2_data[0].y, 2, 0, sizeof(MyImPlot::Vector2f) /* or sizeof(float) * 2 */);
- // custom getter example 2:
- static MyImPlot::WaveData data1(0.001, 0.2, 2, 0.75);
- static MyImPlot::WaveData data2(0.001, 0.2, 4, 0.25);
- ImPlot::PlotLineG("Waves", MyImPlot::SineWave, &data1, 1000);
- ImPlot::PlotLineG("Waves", MyImPlot::SawWave, &data2, 1000);
- ImPlot::PushStyleVar(ImPlotStyleVar_FillAlpha, 0.25f);
- ImPlot::PlotShadedG("Waves", MyImPlot::SineWave, &data1, MyImPlot::SawWave, &data2, 1000);
- ImPlot::PopStyleVar();
+ // custom getter example 1:
+ ImPlot::PlotLineG("Spiral", MyImPlot::Spiral, NULL, 1000);
+
+ // custom getter example 2:
+ static MyImPlot::WaveData data1(0.001, 0.2, 2, 0.75);
+ static MyImPlot::WaveData data2(0.001, 0.2, 4, 0.25);
+ ImPlot::PlotLineG("Waves", MyImPlot::SineWave, &data1, 1000);
+ ImPlot::PlotLineG("Waves", MyImPlot::SawWave, &data2, 1000);
+ ImPlot::PushStyleVar(ImPlotStyleVar_FillAlpha, 0.25f);
+ ImPlot::PlotShadedG("Waves", MyImPlot::SineWave, &data1, MyImPlot::SawWave, &data2, 1000);
+ ImPlot::PopStyleVar();
- // you can also pass C++ lambdas:
- // auto lamda = [](void* data, int idx) { ... return ImPlotPoint(x,y); };
- // ImPlot::PlotLine("My Lambda", lambda, data, 1000);
+ // you can also pass C++ lambdas:
+ // auto lamda = [](void* data, int idx) { ... return ImPlotPoint(x,y); };
+ // ImPlot::PlotLine("My Lambda", lambda, data, 1000);
- ImPlot::EndPlot();
+ ImPlot::EndPlot();
+ }
+}
+
+void MetricFormatter(double value, char* buff, int size, void* data) {
+ const char* unit = (const char*)data;
+ static double v[] = {1000000000,1000000,1000,1,0.001,0.000001,0.000000001};
+ static const char* p[] = {"G","M","k","","m","u","n"};
+ if (value == 0) {
+ snprintf(buff,size,"0 %s", unit);
+ return;
+ }
+ for (int i = 0; i < 7; ++i) {
+ if (fabs(value) >= v[i]) {
+ snprintf(buff,size,"%g %s%s",value/v[i],p[i],unit);
+ return;
}
}
- //-------------------------------------------------------------------------
- if (ImGui::CollapsingHeader("Custom Ticks##")) {
- static bool custom_fmt = true;
- static bool custom_ticks = false;
- static bool custom_labels = true;
- ImGui::Checkbox("Show Custom Format", &custom_fmt);
+ snprintf(buff,size,"%g %s%s",value/v[6],p[6],unit);
+}
+
+void ShowDemo_TickLabels() {
+ static bool custom_fmt = true;
+ static bool custom_ticks = false;
+ static bool custom_labels = true;
+ ImGui::Checkbox("Show Custom Format", &custom_fmt);
+ ImGui::SameLine();
+ ImGui::Checkbox("Show Custom Ticks", &custom_ticks);
+ if (custom_ticks) {
ImGui::SameLine();
- ImGui::Checkbox("Show Custom Ticks", &custom_ticks);
- if (custom_ticks) {
- ImGui::SameLine();
- ImGui::Checkbox("Show Custom Labels", &custom_labels);
- }
- double pi = 3.14;
- const char* pi_str[] = {"PI"};
- static double yticks[] = {1,3,7,9};
- static const char* ylabels[] = {"One","Three","Seven","Nine"};
- static double yticks_aux[] = {0.2,0.4,0.6};
- static const char* ylabels_aux[] = {"A","B","C","D","E","F"};
+ ImGui::Checkbox("Show Custom Labels", &custom_labels);
+ }
+ const double pi = 3.14;
+ const char* pi_str[] = {"PI"};
+ static double yticks[] = {100,300,700,900};
+ static const char* ylabels[] = {"One","Three","Seven","Nine"};
+ static double yticks_aux[] = {0.2,0.4,0.6};
+ static const char* ylabels_aux[] = {"A","B","C","D","E","F"};
+
+ if (ImPlot::BeginPlot("##Ticks")) {
+ ImPlot::SetupAxesLimits(2.5,5,0,1000);
+ ImPlot::SetupAxis(ImAxis_Y2, NULL, ImPlotAxisFlags_AuxDefault);
+ ImPlot::SetupAxis(ImAxis_Y3, NULL, ImPlotAxisFlags_AuxDefault);
if (custom_fmt) {
- ImPlot::SetNextPlotFormatX("%g ms");
- ImPlot::SetNextPlotFormatY("%g Hz", ImPlotYAxis_1);
- ImPlot::SetNextPlotFormatY("%g dB", ImPlotYAxis_2);
- ImPlot::SetNextPlotFormatY("%g km", ImPlotYAxis_3);
+ ImPlot::SetupAxisFormat(ImAxis_X1, "%g ms");
+ ImPlot::SetupAxisFormat(ImAxis_Y1, MetricFormatter, (void*)"Hz");
+ ImPlot::SetupAxisFormat(ImAxis_Y2, "%g dB");
+ ImPlot::SetupAxisFormat(ImAxis_Y3, MetricFormatter, (void*)"m");
}
if (custom_ticks) {
- ImPlot::SetNextPlotTicksX(&pi,1,custom_labels ? pi_str : NULL, true);
- ImPlot::SetNextPlotTicksY(yticks, 4, custom_labels ? ylabels : NULL, ImPlotYAxis_1);
- ImPlot::SetNextPlotTicksY(yticks_aux, 3, custom_labels ? ylabels_aux : NULL, false, ImPlotYAxis_2);
- ImPlot::SetNextPlotTicksY(0, 1, 6, custom_labels ? ylabels_aux : NULL, false, ImPlotYAxis_3);
- }
- ImPlot::SetNextPlotLimits(2.5,5,0,10);
- if (ImPlot::BeginPlot("Custom Ticks", NULL, NULL, ImVec2(-1,0), ImPlotFlags_YAxis2 | ImPlotFlags_YAxis3)) {
- // nothing to see here, just the ticks
- ImPlot::EndPlot();
+ ImPlot::SetupAxisTicks(ImAxis_X1, &pi,1,custom_labels ? pi_str : NULL, true);
+ ImPlot::SetupAxisTicks(ImAxis_Y1, yticks, 4, custom_labels ? ylabels : NULL, false);
+ ImPlot::SetupAxisTicks(ImAxis_Y2, yticks_aux, 3, custom_labels ? ylabels_aux : NULL, false);
+ ImPlot::SetupAxisTicks(ImAxis_Y3, 0, 1, 6, custom_labels ? ylabels_aux : NULL, false);
}
+ ImPlot::EndPlot();
}
- //-------------------------------------------------------------------------
- if (ImGui::CollapsingHeader("Custom Styles")) {
- ImPlot::PushColormap(ImPlotColormap_Deep);
- // normally you wouldn't change the entire style each frame
- ImPlotStyle backup = ImPlot::GetStyle();
- MyImPlot::StyleSeaborn();
- ImPlot::SetNextPlotLimits(-0.5f, 9.5f, 0, 10);
- if (ImPlot::BeginPlot("seaborn style", "x-axis", "y-axis")) {
- unsigned int lin[10] = {8,8,9,7,8,8,8,9,7,8};
- unsigned int bar[10] = {1,2,5,3,4,1,2,5,3,4};
- unsigned int dot[10] = {7,6,6,7,8,5,6,5,8,7};
- ImPlot::PlotBars("Bars", bar, 10, 0.5f);
- ImPlot::PlotLine("Line", lin, 10);
- ImPlot::NextColormapColor(); // skip green
- ImPlot::PlotScatter("Scatter", dot, 10);
- ImPlot::EndPlot();
- }
- ImPlot::GetStyle() = backup;
- ImPlot::PopColormap();
+}
+
+void ShowDemo_CustomStyles() {
+ ImPlot::PushColormap(ImPlotColormap_Deep);
+ // normally you wouldn't change the entire style each frame
+ ImPlotStyle backup = ImPlot::GetStyle();
+ MyImPlot::StyleSeaborn();
+ if (ImPlot::BeginPlot("seaborn style")) {
+ ImPlot::SetupAxes( "x-axis", "y-axis");
+ ImPlot::SetupAxesLimits(-0.5f, 9.5f, 0, 10);
+ unsigned int lin[10] = {8,8,9,7,8,8,8,9,7,8};
+ unsigned int bar[10] = {1,2,5,3,4,1,2,5,3,4};
+ unsigned int dot[10] = {7,6,6,7,8,5,6,5,8,7};
+ ImPlot::PlotBars("Bars", bar, 10, 0.5f);
+ ImPlot::PlotLine("Line", lin, 10);
+ ImPlot::NextColormapColor(); // skip green
+ ImPlot::PlotScatter("Scatter", dot, 10);
+ ImPlot::EndPlot();
}
- //-------------------------------------------------------------------------
- if (ImGui::CollapsingHeader("Custom Rendering")) {
- if (ImPlot::BeginPlot("##CustomRend")) {
- ImVec2 cntr = ImPlot::PlotToPixels(ImPlotPoint(0.5f, 0.5f));
- ImVec2 rmin = ImPlot::PlotToPixels(ImPlotPoint(0.25f, 0.75f));
- ImVec2 rmax = ImPlot::PlotToPixels(ImPlotPoint(0.75f, 0.25f));
- ImPlot::PushPlotClipRect();
- ImPlot::GetPlotDrawList()->AddCircleFilled(cntr,20,IM_COL32(255,255,0,255),20);
- ImPlot::GetPlotDrawList()->AddRect(rmin, rmax, IM_COL32(128,0,255,255));
- ImPlot::PopPlotClipRect();
- ImPlot::EndPlot();
- }
+ ImPlot::GetStyle() = backup;
+ ImPlot::PopColormap();
+}
+
+void ShowDemo_CustomRendering() {
+ if (ImPlot::BeginPlot("##CustomRend")) {
+ ImVec2 cntr = ImPlot::PlotToPixels(ImPlotPoint(0.5f, 0.5f));
+ ImVec2 rmin = ImPlot::PlotToPixels(ImPlotPoint(0.25f, 0.75f));
+ ImVec2 rmax = ImPlot::PlotToPixels(ImPlotPoint(0.75f, 0.25f));
+ ImPlot::PushPlotClipRect();
+ ImPlot::GetPlotDrawList()->AddCircleFilled(cntr,20,IM_COL32(255,255,0,255),20);
+ ImPlot::GetPlotDrawList()->AddRect(rmin, rmax, IM_COL32(128,0,255,255));
+ ImPlot::PopPlotClipRect();
+ ImPlot::EndPlot();
}
- //-------------------------------------------------------------------------
- if (ImGui::CollapsingHeader("Custom Context Menus")) {
- ImGui::BulletText("You can implement legend context menus to inject per-item controls and widgets.");
- ImGui::BulletText("Right click the legend label/icon to edit custom item attributes.");
+}
- static float frequency = 0.1f;
- static float amplitude = 0.5f;
- static ImVec4 color = ImVec4(1,1,0,1);
- static float alpha = 1.0f;
- static bool line = false;
- static float thickness = 1;
- static bool markers = false;
- static bool shaded = false;
+void ShowDemo_LegendPopups() {
+ ImGui::BulletText("You can implement legend context menus to inject per-item controls and widgets.");
+ ImGui::BulletText("Right click the legend label/icon to edit custom item attributes.");
- static float vals[101];
- for (int i = 0; i < 101; ++i)
- vals[i] = amplitude * sinf(frequency * i);
+ static float frequency = 0.1f;
+ static float amplitude = 0.5f;
+ static ImVec4 color = ImVec4(1,1,0,1);
+ static float alpha = 1.0f;
+ static bool line = false;
+ static float thickness = 1;
+ static bool markers = false;
+ static bool shaded = false;
- ImPlot::SetNextPlotLimits(0,100,-1,1);
- if (ImPlot::BeginPlot("Right Click the Legend")) {
- // rendering logic
- ImPlot::PushStyleVar(ImPlotStyleVar_FillAlpha, alpha);
- if (!line) {
- ImPlot::SetNextFillStyle(color);
- ImPlot::PlotBars("Right Click Me", vals, 101);
- }
- else {
- if (markers) ImPlot::SetNextMarkerStyle(ImPlotMarker_Circle);
- ImPlot::SetNextLineStyle(color, thickness);
- ImPlot::PlotLine("Right Click Me", vals, 101);
- if (shaded) ImPlot::PlotShaded("Right Click Me",vals,101);
- }
- ImPlot::PopStyleVar();
- // custom legend context menu
- if (ImPlot::BeginLegendPopup("Right Click Me")) {
- ImGui::SliderFloat("Frequency",&frequency,0,1,"%0.2f");
- ImGui::SliderFloat("Amplitude",&amplitude,0,1,"%0.2f");
- ImGui::Separator();
- ImGui::ColorEdit3("Color",&color.x);
- ImGui::SliderFloat("Transparency",&alpha,0,1,"%.2f");
- ImGui::Checkbox("Line Plot", &line);
- if (line) {
- ImGui::SliderFloat("Thickness", &thickness, 0, 5);
- ImGui::Checkbox("Markers", &markers);
- ImGui::Checkbox("Shaded",&shaded);
- }
- ImPlot::EndLegendPopup();
+ static float vals[101];
+ for (int i = 0; i < 101; ++i)
+ vals[i] = amplitude * sinf(frequency * i);
+
+ if (ImPlot::BeginPlot("Right Click the Legend")) {
+ ImPlot::SetupAxesLimits(0,100,-1,1);
+ // rendering logic
+ ImPlot::PushStyleVar(ImPlotStyleVar_FillAlpha, alpha);
+ if (!line) {
+ ImPlot::SetNextFillStyle(color);
+ ImPlot::PlotBars("Right Click Me", vals, 101);
+ }
+ else {
+ if (markers) ImPlot::SetNextMarkerStyle(ImPlotMarker_Circle);
+ ImPlot::SetNextLineStyle(color, thickness);
+ ImPlot::PlotLine("Right Click Me", vals, 101);
+ if (shaded) ImPlot::PlotShaded("Right Click Me",vals,101);
+ }
+ ImPlot::PopStyleVar();
+ // custom legend context menu
+ if (ImPlot::BeginLegendPopup("Right Click Me")) {
+ ImGui::SliderFloat("Frequency",&frequency,0,1,"%0.2f");
+ ImGui::SliderFloat("Amplitude",&amplitude,0,1,"%0.2f");
+ ImGui::Separator();
+ ImGui::ColorEdit3("Color",&color.x);
+ ImGui::SliderFloat("Transparency",&alpha,0,1,"%.2f");
+ ImGui::Checkbox("Line Plot", &line);
+ if (line) {
+ ImGui::SliderFloat("Thickness", &thickness, 0, 5);
+ ImGui::Checkbox("Markers", &markers);
+ ImGui::Checkbox("Shaded",&shaded);
}
- ImPlot::EndPlot();
+ ImPlot::EndLegendPopup();
}
+ ImPlot::EndPlot();
}
- //-------------------------------------------------------------------------
- if (ImGui::CollapsingHeader("Custom Plotters and Tooltips")) {
- ImGui::BulletText("You can create custom plotters or extend ImPlot using implot_internal.h.");
- double dates[] = {1546300800,1546387200,1546473600,1546560000,1546819200,1546905600,1546992000,1547078400,1547164800,1547424000,1547510400,1547596800,1547683200,1547769600,1547942400,1548028800,1548115200,1548201600,1548288000,1548374400,1548633600,1548720000,1548806400,1548892800,1548979200,1549238400,1549324800,1549411200,1549497600,1549584000,1549843200,1549929600,1550016000,1550102400,1550188800,1550361600,1550448000,1550534400,1550620800,1550707200,1550793600,1551052800,1551139200,1551225600,1551312000,1551398400,1551657600,1551744000,1551830400,1551916800,1552003200,1552262400,1552348800,1552435200,1552521600,1552608000,1552867200,1552953600,1553040000,1553126400,1553212800,1553472000,1553558400,1553644800,1553731200,1553817600,1554076800,1554163200,1554249600,1554336000,1554422400,1554681600,1554768000,1554854400,1554940800,1555027200,1555286400,1555372800,1555459200,1555545600,1555632000,1555891200,1555977600,1556064000,1556150400,1556236800,1556496000,1556582400,1556668800,1556755200,1556841600,1557100800,1557187200,1557273600,1557360000,1557446400,1557705600,1557792000,1557878400,1557964800,1558051200,1558310400,1558396800,1558483200,1558569600,1558656000,1558828800,1558915200,1559001600,1559088000,1559174400,1559260800,1559520000,1559606400,1559692800,1559779200,1559865600,1560124800,1560211200,1560297600,1560384000,1560470400,1560729600,1560816000,1560902400,1560988800,1561075200,1561334400,1561420800,1561507200,1561593600,1561680000,1561939200,1562025600,1562112000,1562198400,1562284800,1562544000,1562630400,1562716800,1562803200,1562889600,1563148800,1563235200,1563321600,1563408000,1563494400,1563753600,1563840000,1563926400,1564012800,1564099200,1564358400,1564444800,1564531200,1564617600,1564704000,1564963200,1565049600,1565136000,1565222400,1565308800,1565568000,1565654400,1565740800,1565827200,1565913600,1566172800,1566259200,1566345600,1566432000,1566518400,1566777600,1566864000,1566950400,1567036800,1567123200,1567296000,1567382400,1567468800,1567555200,1567641600,1567728000,1567987200,1568073600,1568160000,1568246400,1568332800,1568592000,1568678400,1568764800,1568851200,1568937600,1569196800,1569283200,1569369600,1569456000,1569542400,1569801600,1569888000,1569974400,1570060800,1570147200,1570406400,1570492800,1570579200,1570665600,1570752000,1571011200,1571097600,1571184000,1571270400,1571356800,1571616000,1571702400,1571788800,1571875200,1571961600};
- double opens[] = {1284.7,1319.9,1318.7,1328,1317.6,1321.6,1314.3,1325,1319.3,1323.1,1324.7,1321.3,1323.5,1322,1281.3,1281.95,1311.1,1315,1314,1313.1,1331.9,1334.2,1341.3,1350.6,1349.8,1346.4,1343.4,1344.9,1335.6,1337.9,1342.5,1337,1338.6,1337,1340.4,1324.65,1324.35,1349.5,1371.3,1367.9,1351.3,1357.8,1356.1,1356,1347.6,1339.1,1320.6,1311.8,1314,1312.4,1312.3,1323.5,1319.1,1327.2,1332.1,1320.3,1323.1,1328,1330.9,1338,1333,1335.3,1345.2,1341.1,1332.5,1314,1314.4,1310.7,1314,1313.1,1315,1313.7,1320,1326.5,1329.2,1314.2,1312.3,1309.5,1297.4,1293.7,1277.9,1295.8,1295.2,1290.3,1294.2,1298,1306.4,1299.8,1302.3,1297,1289.6,1302,1300.7,1303.5,1300.5,1303.2,1306,1318.7,1315,1314.5,1304.1,1294.7,1293.7,1291.2,1290.2,1300.4,1284.2,1284.25,1301.8,1295.9,1296.2,1304.4,1323.1,1340.9,1341,1348,1351.4,1351.4,1343.5,1342.3,1349,1357.6,1357.1,1354.7,1361.4,1375.2,1403.5,1414.7,1433.2,1438,1423.6,1424.4,1418,1399.5,1435.5,1421.25,1434.1,1412.4,1409.8,1412.2,1433.4,1418.4,1429,1428.8,1420.6,1441,1460.4,1441.7,1438.4,1431,1439.3,1427.4,1431.9,1439.5,1443.7,1425.6,1457.5,1451.2,1481.1,1486.7,1512.1,1515.9,1509.2,1522.3,1513,1526.6,1533.9,1523,1506.3,1518.4,1512.4,1508.8,1545.4,1537.3,1551.8,1549.4,1536.9,1535.25,1537.95,1535.2,1556,1561.4,1525.6,1516.4,1507,1493.9,1504.9,1506.5,1513.1,1506.5,1509.7,1502,1506.8,1521.5,1529.8,1539.8,1510.9,1511.8,1501.7,1478,1485.4,1505.6,1511.6,1518.6,1498.7,1510.9,1510.8,1498.3,1492,1497.7,1484.8,1494.2,1495.6,1495.6,1487.5,1491.1,1495.1,1506.4};
- double highs[] = {1284.75,1320.6,1327,1330.8,1326.8,1321.6,1326,1328,1325.8,1327.1,1326,1326,1323.5,1322.1,1282.7,1282.95,1315.8,1316.3,1314,1333.2,1334.7,1341.7,1353.2,1354.6,1352.2,1346.4,1345.7,1344.9,1340.7,1344.2,1342.7,1342.1,1345.2,1342,1350,1324.95,1330.75,1369.6,1374.3,1368.4,1359.8,1359,1357,1356,1353.4,1340.6,1322.3,1314.1,1316.1,1312.9,1325.7,1323.5,1326.3,1336,1332.1,1330.1,1330.4,1334.7,1341.1,1344.2,1338.8,1348.4,1345.6,1342.8,1334.7,1322.3,1319.3,1314.7,1316.6,1316.4,1315,1325.4,1328.3,1332.2,1329.2,1316.9,1312.3,1309.5,1299.6,1296.9,1277.9,1299.5,1296.2,1298.4,1302.5,1308.7,1306.4,1305.9,1307,1297.2,1301.7,1305,1305.3,1310.2,1307,1308,1319.8,1321.7,1318.7,1316.2,1305.9,1295.8,1293.8,1293.7,1304.2,1302,1285.15,1286.85,1304,1302,1305.2,1323,1344.1,1345.2,1360.1,1355.3,1363.8,1353,1344.7,1353.6,1358,1373.6,1358.2,1369.6,1377.6,1408.9,1425.5,1435.9,1453.7,1438,1426,1439.1,1418,1435,1452.6,1426.65,1437.5,1421.5,1414.1,1433.3,1441.3,1431.4,1433.9,1432.4,1440.8,1462.3,1467,1443.5,1444,1442.9,1447,1437.6,1440.8,1445.7,1447.8,1458.2,1461.9,1481.8,1486.8,1522.7,1521.3,1521.1,1531.5,1546.1,1534.9,1537.7,1538.6,1523.6,1518.8,1518.4,1514.6,1540.3,1565,1554.5,1556.6,1559.8,1541.9,1542.9,1540.05,1558.9,1566.2,1561.9,1536.2,1523.8,1509.1,1506.2,1532.2,1516.6,1519.7,1515,1519.5,1512.1,1524.5,1534.4,1543.3,1543.3,1542.8,1519.5,1507.2,1493.5,1511.4,1525.8,1522.2,1518.8,1515.3,1518,1522.3,1508,1501.5,1503,1495.5,1501.1,1497.9,1498.7,1492.1,1499.4,1506.9,1520.9};
- double lows[] = {1282.85,1315,1318.7,1309.6,1317.6,1312.9,1312.4,1319.1,1319,1321,1318.1,1321.3,1319.9,1312,1280.5,1276.15,1308,1309.9,1308.5,1312.3,1329.3,1333.1,1340.2,1347,1345.9,1338,1340.8,1335,1332,1337.9,1333,1336.8,1333.2,1329.9,1340.4,1323.85,1324.05,1349,1366.3,1351.2,1349.1,1352.4,1350.7,1344.3,1338.9,1316.3,1308.4,1306.9,1309.6,1306.7,1312.3,1315.4,1319,1327.2,1317.2,1320,1323,1328,1323,1327.8,1331.7,1335.3,1336.6,1331.8,1311.4,1310,1309.5,1308,1310.6,1302.8,1306.6,1313.7,1320,1322.8,1311,1312.1,1303.6,1293.9,1293.5,1291,1277.9,1294.1,1286,1289.1,1293.5,1296.9,1298,1299.6,1292.9,1285.1,1288.5,1296.3,1297.2,1298.4,1298.6,1302,1300.3,1312,1310.8,1301.9,1292,1291.1,1286.3,1289.2,1289.9,1297.4,1283.65,1283.25,1292.9,1295.9,1290.8,1304.2,1322.7,1336.1,1341,1343.5,1345.8,1340.3,1335.1,1341.5,1347.6,1352.8,1348.2,1353.7,1356.5,1373.3,1398,1414.7,1427,1416.4,1412.7,1420.1,1396.4,1398.8,1426.6,1412.85,1400.7,1406,1399.8,1404.4,1415.5,1417.2,1421.9,1415,1413.7,1428.1,1434,1435.7,1427.5,1429.4,1423.9,1425.6,1427.5,1434.8,1422.3,1412.1,1442.5,1448.8,1468.2,1484.3,1501.6,1506.2,1498.6,1488.9,1504.5,1518.3,1513.9,1503.3,1503,1506.5,1502.1,1503,1534.8,1535.3,1541.4,1528.6,1525.6,1535.25,1528.15,1528,1542.6,1514.3,1510.7,1505.5,1492.1,1492.9,1496.8,1493.1,1503.4,1500.9,1490.7,1496.3,1505.3,1505.3,1517.9,1507.4,1507.1,1493.3,1470.5,1465,1480.5,1501.7,1501.4,1493.3,1492.1,1505.1,1495.7,1478,1487.1,1480.8,1480.6,1487,1488.3,1484.8,1484,1490.7,1490.4,1503.1};
- double closes[] = {1283.35,1315.3,1326.1,1317.4,1321.5,1317.4,1323.5,1319.2,1321.3,1323.3,1319.7,1325.1,1323.6,1313.8,1282.05,1279.05,1314.2,1315.2,1310.8,1329.1,1334.5,1340.2,1340.5,1350,1347.1,1344.3,1344.6,1339.7,1339.4,1343.7,1337,1338.9,1340.1,1338.7,1346.8,1324.25,1329.55,1369.6,1372.5,1352.4,1357.6,1354.2,1353.4,1346,1341,1323.8,1311.9,1309.1,1312.2,1310.7,1324.3,1315.7,1322.4,1333.8,1319.4,1327.1,1325.8,1330.9,1325.8,1331.6,1336.5,1346.7,1339.2,1334.7,1313.3,1316.5,1312.4,1313.4,1313.3,1312.2,1313.7,1319.9,1326.3,1331.9,1311.3,1313.4,1309.4,1295.2,1294.7,1294.1,1277.9,1295.8,1291.2,1297.4,1297.7,1306.8,1299.4,1303.6,1302.2,1289.9,1299.2,1301.8,1303.6,1299.5,1303.2,1305.3,1319.5,1313.6,1315.1,1303.5,1293,1294.6,1290.4,1291.4,1302.7,1301,1284.15,1284.95,1294.3,1297.9,1304.1,1322.6,1339.3,1340.1,1344.9,1354,1357.4,1340.7,1342.7,1348.2,1355.1,1355.9,1354.2,1362.1,1360.1,1408.3,1411.2,1429.5,1430.1,1426.8,1423.4,1425.1,1400.8,1419.8,1432.9,1423.55,1412.1,1412.2,1412.8,1424.9,1419.3,1424.8,1426.1,1423.6,1435.9,1440.8,1439.4,1439.7,1434.5,1436.5,1427.5,1432.2,1433.3,1441.8,1437.8,1432.4,1457.5,1476.5,1484.2,1519.6,1509.5,1508.5,1517.2,1514.1,1527.8,1531.2,1523.6,1511.6,1515.7,1515.7,1508.5,1537.6,1537.2,1551.8,1549.1,1536.9,1529.4,1538.05,1535.15,1555.9,1560.4,1525.5,1515.5,1511.1,1499.2,1503.2,1507.4,1499.5,1511.5,1513.4,1515.8,1506.2,1515.1,1531.5,1540.2,1512.3,1515.2,1506.4,1472.9,1489,1507.9,1513.8,1512.9,1504.4,1503.9,1512.8,1500.9,1488.7,1497.6,1483.5,1494,1498.3,1494.1,1488.1,1487.5,1495.7,1504.7,1505.3};
- static bool tooltip = true;
- ImGui::Checkbox("Show Tooltip", &tooltip);
- ImGui::SameLine();
- static ImVec4 bullCol = ImVec4(0.000f, 1.000f, 0.441f, 1.000f);
- static ImVec4 bearCol = ImVec4(0.853f, 0.050f, 0.310f, 1.000f);
- ImGui::SameLine(); ImGui::ColorEdit4("##Bull", &bullCol.x, ImGuiColorEditFlags_NoInputs);
- ImGui::SameLine(); ImGui::ColorEdit4("##Bear", &bearCol.x, ImGuiColorEditFlags_NoInputs);
- ImPlot::GetStyle().UseLocalTime = false;
- ImPlot::SetNextPlotFormatY("$%.0f");
- ImPlot::SetNextPlotLimits(1546300800, 1571961600, 1250, 1600);
- if (ImPlot::BeginPlot("Candlestick Chart",NULL,NULL,ImVec2(-1,0),0,ImPlotAxisFlags_Time,ImPlotAxisFlags_AutoFit|ImPlotAxisFlags_RangeFit)) {
- MyImPlot::PlotCandlestick("GOOGL",dates, opens, closes, lows, highs, 218, tooltip, 0.25f, bullCol, bearCol);
- ImPlot::EndPlot();
+}
+
+void ShowDemo_ColormapTools() {
+ static int cmap = 0;
+ if (ImPlot::ColormapButton("Colormap Button",ImVec2(0,0),cmap)) {
+ cmap = (cmap + 1) % ImPlot::GetColormapCount();
+ }
+ ImPlot::ColormapIcon(cmap); ImGui::SameLine(); ImGui::Text("Colormap Icon");
+ ImPlot::ColormapScale("Colormap Scale",0,1,ImVec2(0,0),cmap);
+}
+
+void ShowDemo_CustomPlottersAndTooltips() {
+ ImGui::BulletText("You can create custom plotters or extend ImPlot using implot_internal.h.");
+ double dates[] = {1546300800,1546387200,1546473600,1546560000,1546819200,1546905600,1546992000,1547078400,1547164800,1547424000,1547510400,1547596800,1547683200,1547769600,1547942400,1548028800,1548115200,1548201600,1548288000,1548374400,1548633600,1548720000,1548806400,1548892800,1548979200,1549238400,1549324800,1549411200,1549497600,1549584000,1549843200,1549929600,1550016000,1550102400,1550188800,1550361600,1550448000,1550534400,1550620800,1550707200,1550793600,1551052800,1551139200,1551225600,1551312000,1551398400,1551657600,1551744000,1551830400,1551916800,1552003200,1552262400,1552348800,1552435200,1552521600,1552608000,1552867200,1552953600,1553040000,1553126400,1553212800,1553472000,1553558400,1553644800,1553731200,1553817600,1554076800,1554163200,1554249600,1554336000,1554422400,1554681600,1554768000,1554854400,1554940800,1555027200,1555286400,1555372800,1555459200,1555545600,1555632000,1555891200,1555977600,1556064000,1556150400,1556236800,1556496000,1556582400,1556668800,1556755200,1556841600,1557100800,1557187200,1557273600,1557360000,1557446400,1557705600,1557792000,1557878400,1557964800,1558051200,1558310400,1558396800,1558483200,1558569600,1558656000,1558828800,1558915200,1559001600,1559088000,1559174400,1559260800,1559520000,1559606400,1559692800,1559779200,1559865600,1560124800,1560211200,1560297600,1560384000,1560470400,1560729600,1560816000,1560902400,1560988800,1561075200,1561334400,1561420800,1561507200,1561593600,1561680000,1561939200,1562025600,1562112000,1562198400,1562284800,1562544000,1562630400,1562716800,1562803200,1562889600,1563148800,1563235200,1563321600,1563408000,1563494400,1563753600,1563840000,1563926400,1564012800,1564099200,1564358400,1564444800,1564531200,1564617600,1564704000,1564963200,1565049600,1565136000,1565222400,1565308800,1565568000,1565654400,1565740800,1565827200,1565913600,1566172800,1566259200,1566345600,1566432000,1566518400,1566777600,1566864000,1566950400,1567036800,1567123200,1567296000,1567382400,1567468800,1567555200,1567641600,1567728000,1567987200,1568073600,1568160000,1568246400,1568332800,1568592000,1568678400,1568764800,1568851200,1568937600,1569196800,1569283200,1569369600,1569456000,1569542400,1569801600,1569888000,1569974400,1570060800,1570147200,1570406400,1570492800,1570579200,1570665600,1570752000,1571011200,1571097600,1571184000,1571270400,1571356800,1571616000,1571702400,1571788800,1571875200,1571961600};
+ double opens[] = {1284.7,1319.9,1318.7,1328,1317.6,1321.6,1314.3,1325,1319.3,1323.1,1324.7,1321.3,1323.5,1322,1281.3,1281.95,1311.1,1315,1314,1313.1,1331.9,1334.2,1341.3,1350.6,1349.8,1346.4,1343.4,1344.9,1335.6,1337.9,1342.5,1337,1338.6,1337,1340.4,1324.65,1324.35,1349.5,1371.3,1367.9,1351.3,1357.8,1356.1,1356,1347.6,1339.1,1320.6,1311.8,1314,1312.4,1312.3,1323.5,1319.1,1327.2,1332.1,1320.3,1323.1,1328,1330.9,1338,1333,1335.3,1345.2,1341.1,1332.5,1314,1314.4,1310.7,1314,1313.1,1315,1313.7,1320,1326.5,1329.2,1314.2,1312.3,1309.5,1297.4,1293.7,1277.9,1295.8,1295.2,1290.3,1294.2,1298,1306.4,1299.8,1302.3,1297,1289.6,1302,1300.7,1303.5,1300.5,1303.2,1306,1318.7,1315,1314.5,1304.1,1294.7,1293.7,1291.2,1290.2,1300.4,1284.2,1284.25,1301.8,1295.9,1296.2,1304.4,1323.1,1340.9,1341,1348,1351.4,1351.4,1343.5,1342.3,1349,1357.6,1357.1,1354.7,1361.4,1375.2,1403.5,1414.7,1433.2,1438,1423.6,1424.4,1418,1399.5,1435.5,1421.25,1434.1,1412.4,1409.8,1412.2,1433.4,1418.4,1429,1428.8,1420.6,1441,1460.4,1441.7,1438.4,1431,1439.3,1427.4,1431.9,1439.5,1443.7,1425.6,1457.5,1451.2,1481.1,1486.7,1512.1,1515.9,1509.2,1522.3,1513,1526.6,1533.9,1523,1506.3,1518.4,1512.4,1508.8,1545.4,1537.3,1551.8,1549.4,1536.9,1535.25,1537.95,1535.2,1556,1561.4,1525.6,1516.4,1507,1493.9,1504.9,1506.5,1513.1,1506.5,1509.7,1502,1506.8,1521.5,1529.8,1539.8,1510.9,1511.8,1501.7,1478,1485.4,1505.6,1511.6,1518.6,1498.7,1510.9,1510.8,1498.3,1492,1497.7,1484.8,1494.2,1495.6,1495.6,1487.5,1491.1,1495.1,1506.4};
+ double highs[] = {1284.75,1320.6,1327,1330.8,1326.8,1321.6,1326,1328,1325.8,1327.1,1326,1326,1323.5,1322.1,1282.7,1282.95,1315.8,1316.3,1314,1333.2,1334.7,1341.7,1353.2,1354.6,1352.2,1346.4,1345.7,1344.9,1340.7,1344.2,1342.7,1342.1,1345.2,1342,1350,1324.95,1330.75,1369.6,1374.3,1368.4,1359.8,1359,1357,1356,1353.4,1340.6,1322.3,1314.1,1316.1,1312.9,1325.7,1323.5,1326.3,1336,1332.1,1330.1,1330.4,1334.7,1341.1,1344.2,1338.8,1348.4,1345.6,1342.8,1334.7,1322.3,1319.3,1314.7,1316.6,1316.4,1315,1325.4,1328.3,1332.2,1329.2,1316.9,1312.3,1309.5,1299.6,1296.9,1277.9,1299.5,1296.2,1298.4,1302.5,1308.7,1306.4,1305.9,1307,1297.2,1301.7,1305,1305.3,1310.2,1307,1308,1319.8,1321.7,1318.7,1316.2,1305.9,1295.8,1293.8,1293.7,1304.2,1302,1285.15,1286.85,1304,1302,1305.2,1323,1344.1,1345.2,1360.1,1355.3,1363.8,1353,1344.7,1353.6,1358,1373.6,1358.2,1369.6,1377.6,1408.9,1425.5,1435.9,1453.7,1438,1426,1439.1,1418,1435,1452.6,1426.65,1437.5,1421.5,1414.1,1433.3,1441.3,1431.4,1433.9,1432.4,1440.8,1462.3,1467,1443.5,1444,1442.9,1447,1437.6,1440.8,1445.7,1447.8,1458.2,1461.9,1481.8,1486.8,1522.7,1521.3,1521.1,1531.5,1546.1,1534.9,1537.7,1538.6,1523.6,1518.8,1518.4,1514.6,1540.3,1565,1554.5,1556.6,1559.8,1541.9,1542.9,1540.05,1558.9,1566.2,1561.9,1536.2,1523.8,1509.1,1506.2,1532.2,1516.6,1519.7,1515,1519.5,1512.1,1524.5,1534.4,1543.3,1543.3,1542.8,1519.5,1507.2,1493.5,1511.4,1525.8,1522.2,1518.8,1515.3,1518,1522.3,1508,1501.5,1503,1495.5,1501.1,1497.9,1498.7,1492.1,1499.4,1506.9,1520.9};
+ double lows[] = {1282.85,1315,1318.7,1309.6,1317.6,1312.9,1312.4,1319.1,1319,1321,1318.1,1321.3,1319.9,1312,1280.5,1276.15,1308,1309.9,1308.5,1312.3,1329.3,1333.1,1340.2,1347,1345.9,1338,1340.8,1335,1332,1337.9,1333,1336.8,1333.2,1329.9,1340.4,1323.85,1324.05,1349,1366.3,1351.2,1349.1,1352.4,1350.7,1344.3,1338.9,1316.3,1308.4,1306.9,1309.6,1306.7,1312.3,1315.4,1319,1327.2,1317.2,1320,1323,1328,1323,1327.8,1331.7,1335.3,1336.6,1331.8,1311.4,1310,1309.5,1308,1310.6,1302.8,1306.6,1313.7,1320,1322.8,1311,1312.1,1303.6,1293.9,1293.5,1291,1277.9,1294.1,1286,1289.1,1293.5,1296.9,1298,1299.6,1292.9,1285.1,1288.5,1296.3,1297.2,1298.4,1298.6,1302,1300.3,1312,1310.8,1301.9,1292,1291.1,1286.3,1289.2,1289.9,1297.4,1283.65,1283.25,1292.9,1295.9,1290.8,1304.2,1322.7,1336.1,1341,1343.5,1345.8,1340.3,1335.1,1341.5,1347.6,1352.8,1348.2,1353.7,1356.5,1373.3,1398,1414.7,1427,1416.4,1412.7,1420.1,1396.4,1398.8,1426.6,1412.85,1400.7,1406,1399.8,1404.4,1415.5,1417.2,1421.9,1415,1413.7,1428.1,1434,1435.7,1427.5,1429.4,1423.9,1425.6,1427.5,1434.8,1422.3,1412.1,1442.5,1448.8,1468.2,1484.3,1501.6,1506.2,1498.6,1488.9,1504.5,1518.3,1513.9,1503.3,1503,1506.5,1502.1,1503,1534.8,1535.3,1541.4,1528.6,1525.6,1535.25,1528.15,1528,1542.6,1514.3,1510.7,1505.5,1492.1,1492.9,1496.8,1493.1,1503.4,1500.9,1490.7,1496.3,1505.3,1505.3,1517.9,1507.4,1507.1,1493.3,1470.5,1465,1480.5,1501.7,1501.4,1493.3,1492.1,1505.1,1495.7,1478,1487.1,1480.8,1480.6,1487,1488.3,1484.8,1484,1490.7,1490.4,1503.1};
+ double closes[] = {1283.35,1315.3,1326.1,1317.4,1321.5,1317.4,1323.5,1319.2,1321.3,1323.3,1319.7,1325.1,1323.6,1313.8,1282.05,1279.05,1314.2,1315.2,1310.8,1329.1,1334.5,1340.2,1340.5,1350,1347.1,1344.3,1344.6,1339.7,1339.4,1343.7,1337,1338.9,1340.1,1338.7,1346.8,1324.25,1329.55,1369.6,1372.5,1352.4,1357.6,1354.2,1353.4,1346,1341,1323.8,1311.9,1309.1,1312.2,1310.7,1324.3,1315.7,1322.4,1333.8,1319.4,1327.1,1325.8,1330.9,1325.8,1331.6,1336.5,1346.7,1339.2,1334.7,1313.3,1316.5,1312.4,1313.4,1313.3,1312.2,1313.7,1319.9,1326.3,1331.9,1311.3,1313.4,1309.4,1295.2,1294.7,1294.1,1277.9,1295.8,1291.2,1297.4,1297.7,1306.8,1299.4,1303.6,1302.2,1289.9,1299.2,1301.8,1303.6,1299.5,1303.2,1305.3,1319.5,1313.6,1315.1,1303.5,1293,1294.6,1290.4,1291.4,1302.7,1301,1284.15,1284.95,1294.3,1297.9,1304.1,1322.6,1339.3,1340.1,1344.9,1354,1357.4,1340.7,1342.7,1348.2,1355.1,1355.9,1354.2,1362.1,1360.1,1408.3,1411.2,1429.5,1430.1,1426.8,1423.4,1425.1,1400.8,1419.8,1432.9,1423.55,1412.1,1412.2,1412.8,1424.9,1419.3,1424.8,1426.1,1423.6,1435.9,1440.8,1439.4,1439.7,1434.5,1436.5,1427.5,1432.2,1433.3,1441.8,1437.8,1432.4,1457.5,1476.5,1484.2,1519.6,1509.5,1508.5,1517.2,1514.1,1527.8,1531.2,1523.6,1511.6,1515.7,1515.7,1508.5,1537.6,1537.2,1551.8,1549.1,1536.9,1529.4,1538.05,1535.15,1555.9,1560.4,1525.5,1515.5,1511.1,1499.2,1503.2,1507.4,1499.5,1511.5,1513.4,1515.8,1506.2,1515.1,1531.5,1540.2,1512.3,1515.2,1506.4,1472.9,1489,1507.9,1513.8,1512.9,1504.4,1503.9,1512.8,1500.9,1488.7,1497.6,1483.5,1494,1498.3,1494.1,1488.1,1487.5,1495.7,1504.7,1505.3};
+ static bool tooltip = true;
+ ImGui::Checkbox("Show Tooltip", &tooltip);
+ ImGui::SameLine();
+ static ImVec4 bullCol = ImVec4(0.000f, 1.000f, 0.441f, 1.000f);
+ static ImVec4 bearCol = ImVec4(0.853f, 0.050f, 0.310f, 1.000f);
+ ImGui::SameLine(); ImGui::ColorEdit4("##Bull", &bullCol.x, ImGuiColorEditFlags_NoInputs);
+ ImGui::SameLine(); ImGui::ColorEdit4("##Bear", &bearCol.x, ImGuiColorEditFlags_NoInputs);
+ ImPlot::GetStyle().UseLocalTime = false;
+
+ if (ImPlot::BeginPlot("Candlestick Chart",ImVec2(-1,0))) {
+ ImPlot::SetupAxes(NULL,NULL,ImPlotAxisFlags_Time,ImPlotAxisFlags_AutoFit|ImPlotAxisFlags_RangeFit);
+ ImPlot::SetupAxesLimits(1546300800, 1571961600, 1250, 1600);
+ ImPlot::SetupAxisFormat(ImAxis_Y1, "$%.0f");
+ MyImPlot::PlotCandlestick("GOOGL",dates, opens, closes, lows, highs, 218, tooltip, 0.25f, bullCol, bearCol);
+ ImPlot::EndPlot();
+ }
+ }
+
+//-----------------------------------------------------------------------------
+// DEMO WINDOW
+//-----------------------------------------------------------------------------
+
+void ShowDemoWindow(bool* p_open) {
+ static bool show_imgui_metrics = false;
+ static bool show_implot_metrics = false;
+ static bool show_imgui_style_editor = false;
+ static bool show_implot_style_editor = false;
+ static bool show_implot_benchmark = false;
+ if (show_imgui_metrics) {
+ ImGui::ShowMetricsWindow(&show_imgui_metrics);
+ }
+ if (show_implot_metrics) {
+ ImPlot::ShowMetricsWindow(&show_implot_metrics);
+ }
+ if (show_imgui_style_editor) {
+ ImGui::Begin("Style Editor (ImGui)", &show_imgui_style_editor);
+ ImGui::ShowStyleEditor();
+ ImGui::End();
+ }
+ if (show_implot_style_editor) {
+ ImGui::SetNextWindowSize(ImVec2(415,762), ImGuiCond_Appearing);
+ ImGui::Begin("Style Editor (ImPlot)", &show_implot_style_editor);
+ ImPlot::ShowStyleEditor();
+ ImGui::End();
+ }
+ if (show_implot_benchmark) {
+ ImGui::SetNextWindowSize(ImVec2(530,740), ImGuiCond_Appearing);
+ ImGui::Begin("ImPlot Benchmark Tool", &show_implot_benchmark);
+ ImPlot::ShowBenchmarkTool();
+ ImGui::End();
+ return;
+ }
+ ImGui::SetNextWindowPos(ImVec2(50, 50), ImGuiCond_FirstUseEver);
+ ImGui::SetNextWindowSize(ImVec2(600, 750), ImGuiCond_FirstUseEver);
+ ImGui::Begin("ImPlot Demo", p_open, ImGuiWindowFlags_MenuBar);
+ if (ImGui::BeginMenuBar()) {
+ if (ImGui::BeginMenu("Tools")) {
+ ImGui::MenuItem("Metrics (ImGui)", NULL, &show_imgui_metrics);
+ ImGui::MenuItem("Metrics (ImPlot)", NULL, &show_implot_metrics);
+ ImGui::MenuItem("Style Editor (ImGui)", NULL, &show_imgui_style_editor);
+ ImGui::MenuItem("Style Editor (ImPlot)", NULL, &show_implot_style_editor);
+ ImGui::MenuItem("Benchmark", NULL, &show_implot_benchmark);
+ ImGui::EndMenu();
}
+ ImGui::EndMenuBar();
}
//-------------------------------------------------------------------------
+ ImGui::Text("ImPlot says hello. (%s)", IMPLOT_VERSION);
+ // display warning about 16-bit indices
+ static bool showWarning = sizeof(ImDrawIdx)*8 == 16 && (ImGui::GetIO().BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset) == false;
+ if (showWarning) {
+ ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1,1,0,1));
+ ImGui::TextWrapped("WARNING: ImDrawIdx is 16-bit and ImGuiBackendFlags_RendererHasVtxOffset is false. Expect visual glitches and artifacts! See README for more information.");
+ ImGui::PopStyleColor();
+ }
+
+ ImGui::Spacing();
+
+ if (ImGui::BeginTabBar("ImPlotDemoTabs")) {
+ if (ImGui::BeginTabItem("Plots")) {
+ if (ImGui::CollapsingHeader("Line Plots"))
+ ShowDemo_LinePlots();
+ if (ImGui::CollapsingHeader("Filled Line Plots"))
+ ShowDemo_FilledLinePlots();
+ if (ImGui::CollapsingHeader("Shaded Plots##"))
+ ShowDemo_ShadedPlots();
+ if (ImGui::CollapsingHeader("Scatter Plots"))
+ ShowDemo_ScatterPlots();
+ if (ImGui::CollapsingHeader("Realtime Plots"))
+ ShowDemo_RealtimePlots();
+ if (ImGui::CollapsingHeader("Stairstep Plots"))
+ ShowDemo_StairstepPlots();
+ if (ImGui::CollapsingHeader("Bar Plots"))
+ ShowDemo_BarPlots();
+ if (ImGui::CollapsingHeader("Bar Groups"))
+ ShowDemo_BarGroups();
+ if (ImGui::CollapsingHeader("Bar Stacks"))
+ ShowDemo_BarStacks();
+ if (ImGui::CollapsingHeader("Error Bars"))
+ ShowDemo_ErrorBars();
+ if (ImGui::CollapsingHeader("Stem Plots##"))
+ ShowDemo_StemPlots();
+ if (ImGui::CollapsingHeader("Infinite Lines"))
+ ShowDemo_InfiniteLines();
+ if (ImGui::CollapsingHeader("Pie Charts"))
+ ShowDemo_PieCharts();
+ if (ImGui::CollapsingHeader("Heatmaps"))
+ ShowDemo_Heatmaps();
+ if (ImGui::CollapsingHeader("Histogram"))
+ ShowDemo_Histogram();
+ if (ImGui::CollapsingHeader("Histogram 2D"))
+ ShowDemo_Histogram2D();
+ if (ImGui::CollapsingHeader("Digital Plots"))
+ ShowDemo_DigitalPlots();
+ if (ImGui::CollapsingHeader("Images"))
+ ShowDemo_Images();
+ if (ImGui::CollapsingHeader("Markers and Text"))
+ ShowDemo_MarkersAndText();
+ ImGui::EndTabItem();
+ }
+ if (ImGui::BeginTabItem("Subplots")) {
+ if (ImGui::CollapsingHeader("Sizing"))
+ ShowDemo_SubplotsSizing();
+ if (ImGui::CollapsingHeader("Item Sharing"))
+ ShowDemo_SubplotItemSharing();
+ if (ImGui::CollapsingHeader("Axis Linking"))
+ ShowDemo_SubplotAxisLinking();
+ if (ImGui::CollapsingHeader("Tables"))
+ ShowDemo_Tables();
+ ImGui::EndTabItem();
+ }
+ if (ImGui::BeginTabItem("Axes")) {
+ if (ImGui::CollapsingHeader("Log Axes"))
+ ShowDemo_LogAxes();
+ if (ImGui::CollapsingHeader("Time Axes"))
+ ShowDemo_TimeAxes();
+ if (ImGui::CollapsingHeader("Multiple Axes"))
+ ShowDemo_MultipleAxes();
+ if (ImGui::CollapsingHeader("Tick Labels"))
+ ShowDemo_TickLabels();
+ if (ImGui::CollapsingHeader("Linked Axes"))
+ ShowDemo_LinkedAxes();
+ if (ImGui::CollapsingHeader("Equal Axes"))
+ ShowDemo_EqualAxes();
+ if (ImGui::CollapsingHeader("Auto-Fitting Data"))
+ ShowDemo_AutoFittingData();
+ ImGui::EndTabItem();
+ }
+ if (ImGui::BeginTabItem("Tools")) {
+ if (ImGui::CollapsingHeader("Offset and Stride"))
+ ShowDemo_OffsetAndStride();
+ if (ImGui::CollapsingHeader("Drag Points"))
+ ShowDemo_DragPoints();
+ if (ImGui::CollapsingHeader("Drag Lines"))
+ ShowDemo_DragLines();
+ if (ImGui::CollapsingHeader("Drag Rects"))
+ ShowDemo_DragRects();
+ if (ImGui::CollapsingHeader("Querying"))
+ ShowDemo_Querying();
+ if (ImGui::CollapsingHeader("Annotations"))
+ ShowDemo_Annotations();
+ if (ImGui::CollapsingHeader("Tags"))
+ ShowDemo_Tags();
+ if (ImGui::CollapsingHeader("Drag and Drop"))
+ ShowDemo_DragAndDrop();
+ if (ImGui::CollapsingHeader("Legend Options"))
+ ShowDemo_LegendOptions();
+ if (ImGui::CollapsingHeader("Legend Popups"))
+ ShowDemo_LegendPopups();
+ if (ImGui::CollapsingHeader("Colormap Tools"))
+ ShowDemo_ColormapTools();
+ ImGui::EndTabItem();
+ }
+ if (ImGui::BeginTabItem("Custom")) {
+ if (ImGui::CollapsingHeader("Custom Styles"))
+ ShowDemo_CustomStyles();
+ if (ImGui::CollapsingHeader("Custom Data and Getters"))
+ ShowDemo_CustomDataAndGetters();
+ if (ImGui::CollapsingHeader("Custom Rendering"))
+ ShowDemo_CustomRendering();
+ if (ImGui::CollapsingHeader("Custom Plotters and Tooltips"))
+ ShowDemo_CustomPlottersAndTooltips();
+ ImGui::EndTabItem();
+ }
+ if (ImGui::BeginTabItem("Config")) {
+ ShowDemo_Config();
+ ImGui::EndTabItem();
+ }
+ if (ImGui::BeginTabItem("Help")) {
+ ShowDemo_Help();
+ ImGui::EndTabItem();
+ }
+ ImGui::EndTabBar();
+ }
ImGui::End();
}
@@ -1622,11 +2138,11 @@ ImPlotPoint Spiral(void*, int idx) {
0.5f + (a + b*Th / (2.0f * (float)3.14))*sin(Th));
}
-// Example for Tables section. Generates a quick and simple shaded line plot. See implementation at bottom.
void Sparkline(const char* id, const float* values, int count, float min_v, float max_v, int offset, const ImVec4& col, const ImVec2& size) {
ImPlot::PushStyleVar(ImPlotStyleVar_PlotPadding, ImVec2(0,0));
- ImPlot::SetNextPlotLimits(0, count - 1, min_v, max_v, ImGuiCond_Always);
- if (ImPlot::BeginPlot(id,0,0,size,ImPlotFlags_CanvasOnly|ImPlotFlags_NoChild,ImPlotAxisFlags_NoDecorations,ImPlotAxisFlags_NoDecorations)) {
+ if (ImPlot::BeginPlot(id,size,ImPlotFlags_CanvasOnly|ImPlotFlags_NoChild)) {
+ ImPlot::SetupAxes(0,0,ImPlotAxisFlags_NoDecorations,ImPlotAxisFlags_NoDecorations);
+ ImPlot::SetupAxesLimits(0, count - 1, min_v, max_v, ImGuiCond_Always);
ImPlot::PushStyleColor(ImPlotCol_Line, col);
ImPlot::PlotLine(id, values, count, 1, 0, offset);
ImPlot::PushStyleVar(ImPlotStyleVar_FillAlpha, 0.25f);
@@ -1656,16 +2172,11 @@ void StyleSeaborn() {
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_AxisText] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f);
+ colors[ImPlotCol_AxisGrid] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
+ colors[ImPlotCol_AxisBgHovered] = ImVec4(0.92f, 0.92f, 0.95f, 1.00f);
+ colors[ImPlotCol_AxisBgActive] = ImVec4(0.92f, 0.92f, 0.95f, 0.75f);
colors[ImPlotCol_Selection] = ImVec4(1.00f, 0.65f, 0.00f, 1.00f);
- colors[ImPlotCol_Query] = ImVec4(0.23f, 0.10f, 0.64f, 1.00f);
colors[ImPlotCol_Crosshairs] = ImVec4(0.23f, 0.10f, 0.64f, 0.50f);
style.LineWeight = 1.5;
@@ -1688,7 +2199,7 @@ void StyleSeaborn() {
style.PlotPadding = ImVec2(12,12);
style.LabelPadding = ImVec2(5,5);
style.LegendPadding = ImVec2(5,5);
- style.MousePosPadding = ImVec2(5,5);
+ style.MousePosPadding = ImVec2(5,5);
style.PlotMinSize = ImVec2(300,225);
}
@@ -1804,9 +2315,10 @@ struct BenchData {
enum BenchMode {
Line = 0,
- Shaded = 1,
- Scatter = 2,
- Bars = 3
+ LineG = 1,
+ Shaded = 2,
+ Scatter = 3,
+ Bars = 4
};
struct BenchRecord {
@@ -1815,6 +2327,11 @@ struct BenchRecord {
ImVector<ImPlotPoint> Data;
};
+ImPlotPoint BenchmarkGetter(void* data, int idx) {
+ float* values = (float*)data;
+ return ImPlotPoint(idx, values[idx]);
+}
+
void ShowBenchmarkTool() {
static const int max_items = 500;
static BenchData items[max_items];
@@ -1824,7 +2341,7 @@ void ShowBenchmarkTool() {
static int F = 0;
static double t1, t2;
static int mode = BenchMode::Line;
- const char* names[] = {"Line","Shaded","Scatter","Bars"};
+ const char* names[] = {"Line","LineG","Shaded","Scatter","Bars"};
static ImVector<BenchRecord> records;
@@ -1873,8 +2390,9 @@ void ShowBenchmarkTool() {
ImGui::ProgressBar((float)L / (float)(max_items - 1));
- ImPlot::SetNextPlotLimits(0,1000,0,1,ImGuiCond_Always);
- if (ImPlot::BeginPlot("##Bench",NULL,NULL,ImVec2(-1,0),ImPlotFlags_NoChild | ImPlotFlags_CanvasOnly,ImPlotAxisFlags_NoDecorations,ImPlotAxisFlags_NoDecorations)) {
+ if (ImPlot::BeginPlot("##Bench",ImVec2(-1,0),ImPlotFlags_NoChild | ImPlotFlags_CanvasOnly)) {
+ ImPlot::SetupAxes(NULL,NULL,ImPlotAxisFlags_NoDecorations,ImPlotAxisFlags_NoDecorations);
+ ImPlot::SetupAxesLimits(0,1000,0,1,ImGuiCond_Always);
if (running) {
if (mode == BenchMode::Line) {
for (int i = 0; i < L; ++i) {
@@ -1884,6 +2402,14 @@ void ShowBenchmarkTool() {
ImGui::PopID();
}
}
+ else if (mode == BenchMode::LineG) {
+ for (int i = 0; i < L; ++i) {
+ ImGui::PushID(i);
+ ImPlot::SetNextLineStyle(items[i].Col);
+ ImPlot::PlotLineG("##item",BenchmarkGetter,items[i].Data,1000);
+ ImGui::PopID();
+ }
+ }
else if (mode == BenchMode::Shaded) {
for (int i = 0; i < L; ++i) {
ImGui::PushID(i);
@@ -1911,9 +2437,10 @@ void ShowBenchmarkTool() {
}
ImPlot::EndPlot();
}
- ImPlot::SetNextPlotLimits(0,500,0,500,ImGuiCond_Always);
static char buffer[64];
- if (ImPlot::BeginPlot("##Stats", "Items (1,000 pts each)", "Framerate (Hz)", ImVec2(-1,0), ImPlotFlags_NoChild)) {
+ if (ImPlot::BeginPlot("##Stats", ImVec2(-1,0), ImPlotFlags_NoChild)) {
+ ImPlot::SetupAxes("Items (1,000 pts each)", "Framerate (Hz)");
+ ImPlot::SetupAxesLimits(0,500,0,500,ImGuiCond_Always);
for (int run = 0; run < records.size(); ++run) {
if (records[run].Data.Size > 1) {
sprintf(buffer, "B%d-%s%s", run + 1, names[records[run].Mode], records[run].AA ? "-AA" : "");
diff --git a/3rdparty/implot/implot_internal.h b/3rdparty/implot/implot_internal.h
index 3c0d1d5..7895afe 100644
--- a/3rdparty/implot/implot_internal.h
+++ b/3rdparty/implot/implot_internal.h
@@ -20,7 +20,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
-// ImPlot v0.10 WIP
+// ImPlot v0.13 WIP
// You may use this file to debug, understand or extend ImPlot features but we
// don't provide any guarantee of forward compatibility!
@@ -42,6 +42,12 @@
#error Must include implot.h before implot_internal.h
#endif
+
+// Support for pre-1.84 versions. ImPool's GetSize() -> GetBufSize()
+#if (IMGUI_VERSION_NUM < 18303)
+#define GetBufSize GetSize
+#endif
+
//-----------------------------------------------------------------------------
// [SECTION] Constants
//-----------------------------------------------------------------------------
@@ -49,21 +55,24 @@
// Constants can be changed unless stated otherwise. We may move some of these
// to ImPlotStyleVar_ over time.
-// The maximum number of supported y-axes (DO NOT CHANGE THIS)
-#define IMPLOT_Y_AXES 3
-// Zoom rate for scroll (e.g. 0.1f = 10% plot range every scroll click)
-#define IMPLOT_ZOOM_RATE 0.1f
// Mimimum allowable timestamp value 01/01/1970 @ 12:00am (UTC) (DO NOT DECREASE THIS)
#define IMPLOT_MIN_TIME 0
// Maximum allowable timestamp value 01/01/3000 @ 12:00am (UTC) (DO NOT INCREASE THIS)
#define IMPLOT_MAX_TIME 32503680000
// Default label format for axis labels
-#define IMPLOT_LABEL_FMT "%g"
+#define IMPLOT_LABEL_FORMAT "%g"
+// Max character size for tick labels
+#define IMPLOT_LABEL_MAX_SIZE 32
+// Plot values less than or equal to 0 will be replaced with this on log scale axes
+#define IMPLOT_LOG_ZERO DBL_MIN
//-----------------------------------------------------------------------------
// [SECTION] Macros
//-----------------------------------------------------------------------------
+#define IMPLOT_NUM_X_AXES ImAxis_Y1
+#define IMPLOT_NUM_Y_AXES (ImAxis_COUNT - IMPLOT_NUM_X_AXES)
+
// Split ImU32 color into RGB components [0 255]
#define IM_COL32_SPLIT_RGB(col,r,g,b) \
ImU32 r = ((col >> IM_COL32_R_SHIFT) & 0xFF); \
@@ -78,7 +87,7 @@ struct ImPlotTick;
struct ImPlotAxis;
struct ImPlotAxisColor;
struct ImPlotItem;
-struct ImPlotLegendData;
+struct ImPlotLegend;
struct ImPlotPlot;
struct ImPlotNextPlotData;
@@ -86,7 +95,9 @@ struct ImPlotNextPlotData;
// [SECTION] Context Pointer
//-----------------------------------------------------------------------------
+#ifndef GImPlot
extern IMPLOT_API ImPlotContext* GImPlot; // Current implicit context pointer
+#endif
//-----------------------------------------------------------------------------
// [SECTION] Generic Helpers
@@ -110,11 +121,11 @@ static inline T ImRemap01(T x, T x0, T x1) { return (x - x0) / (x1 - x0); }
// Returns always positive modulo (assumes r != 0)
static inline int ImPosMod(int l, int r) { return (l % r + r) % r; }
// Returns true if val is NAN or INFINITY
-static inline bool ImNanOrInf(double val) { return val == HUGE_VAL || val == -HUGE_VAL || isnan(val); }
+static inline bool ImNanOrInf(double val) { return !(val >= -DBL_MAX && val <= DBL_MAX) || isnan(val); }
// Turns NANs to 0s
static inline double ImConstrainNan(double val) { return isnan(val) ? 0 : val; }
// Turns infinity to floating point maximums
-static inline double ImConstrainInf(double val) { return val == HUGE_VAL ? DBL_MAX : val == -HUGE_VAL ? - DBL_MAX : val; }
+static inline double ImConstrainInf(double val) { return val >= DBL_MAX ? DBL_MAX : val <= -DBL_MAX ? - DBL_MAX : val; }
// Turns numbers less than or equal to 0 to 0.001 (sort of arbitrary, is there a better way?)
static inline double ImConstrainLog(double val) { return val <= 0 ? 0.001f : val; }
// Turns numbers less than 0 to zero
@@ -137,6 +148,14 @@ static inline void ImMinMaxArray(const T* values, int count, T* min_out, T* max_
}
*min_out = Min; *max_out = Max;
}
+// Finds the sim of an array
+template <typename T>
+static inline T ImSum(const T* values, int count) {
+ T sum = 0;
+ for (int i = 0; i < count; ++i)
+ sum += values[i];
+ return sum;
+}
// Finds the mean of an array
template <typename T>
static inline double ImMean(const T* values, int count) {
@@ -196,42 +215,6 @@ static inline ImU32 ImAlphaU32(ImU32 col, float alpha) {
return col & ~((ImU32)((1.0f-alpha)*255)<<IM_COL32_A_SHIFT);
}
-// Character buffer writer helper (FIXME: Can't we replace this with ImGuiTextBuffer?)
-struct ImBufferWriter
-{
- char* Buffer;
- int Size;
- int Pos;
-
- ImBufferWriter(char* buffer, int size) {
- Buffer = buffer;
- Size = size;
- Pos = 0;
- }
-
- void Write(const char* fmt, ...) {
- va_list args;
- va_start(args, fmt);
- WriteV(fmt, args);
- va_end(args);
- }
-
- void WriteV(const char* fmt, va_list args) {
- const int written = ::vsnprintf(&Buffer[Pos], Size - Pos - 1, fmt, args);
- if (written > 0)
- Pos += ImMin(written, Size-Pos-1);
- }
-};
-
-// Fixed size point array
-template <int N>
-struct ImPlotPointArray {
- inline ImPlotPoint& operator[](int i) { return Data[i]; }
- inline const ImPlotPoint& operator[](int i) const { return Data[i]; }
- inline int Size() { return N; }
- ImPlotPoint Data[N];
-};
-
//-----------------------------------------------------------------------------
// [SECTION] ImPlot Enums
//-----------------------------------------------------------------------------
@@ -282,23 +265,6 @@ enum ImPlotTimeFmt_ { // default [ 24 Hour Clock ]
ImPlotTimeFmt_Hr // 7pm [ 19:00 ]
};
-// Input mapping structure, default values listed in the comments.
-struct ImPlotInputMap {
- ImGuiMouseButton PanButton; // LMB enables panning when held
- ImGuiKeyModFlags PanMod; // none optional modifier that must be held for panning
- ImGuiMouseButton FitButton; // LMB fits visible data when double clicked
- ImGuiMouseButton ContextMenuButton; // RMB opens plot context menu (if enabled) when clicked
- ImGuiMouseButton BoxSelectButton; // RMB begins box selection when pressed and confirms selection when released
- ImGuiKeyModFlags BoxSelectMod; // none optional modifier that must be held for box selection
- ImGuiMouseButton BoxSelectCancelButton; // LMB cancels active box selection when pressed
- ImGuiMouseButton QueryButton; // MMB begins query selection when pressed and end query selection when released
- ImGuiKeyModFlags QueryMod; // none optional modifier that must be held for query selection
- ImGuiKeyModFlags QueryToggleMod; // Ctrl when held, active box selections turn into queries
- ImGuiKeyModFlags HorizontalMod; // Alt expands active box selection/query horizontally to plot edge when held
- ImGuiKeyModFlags VerticalMod; // Shift expands active box selection/query vertically to plot edge when held
- IMPLOT_API ImPlotInputMap();
-};
-
//-----------------------------------------------------------------------------
// [SECTION] ImPlot Structs
//-----------------------------------------------------------------------------
@@ -504,6 +470,54 @@ struct ImPlotAnnotationCollection {
}
};
+struct ImPlotTag {
+ ImAxis Axis;
+ double Value;
+ ImU32 ColorBg;
+ ImU32 ColorFg;
+ int TextOffset;
+};
+
+struct ImPlotTagCollection {
+
+ ImVector<ImPlotTag> Tags;
+ ImGuiTextBuffer TextBuffer;
+ int Size;
+
+ ImPlotTagCollection() { Reset(); }
+
+ void AppendV(ImAxis axis, double value, ImU32 bg, ImU32 fg, const char* fmt, va_list args) IM_FMTLIST(6) {
+ ImPlotTag tag;
+ tag.Axis = axis;
+ tag.Value = value;
+ tag.ColorBg = bg;
+ tag.ColorFg = fg;
+ tag.TextOffset = TextBuffer.size();
+ Tags.push_back(tag);
+ TextBuffer.appendfv(fmt, args);
+ const char nul[] = "";
+ TextBuffer.append(nul,nul+1);
+ Size++;
+ }
+
+ void Append(ImAxis axis, double value, ImU32 bg, ImU32 fg, const char* fmt, ...) IM_FMTARGS(6) {
+ va_list args;
+ va_start(args, fmt);
+ AppendV(axis, value, bg, fg, fmt, args);
+ va_end(args);
+ }
+
+ const char* GetText(int idx) {
+ return TextBuffer.Buf.Data + Tags[idx].TextOffset;
+ }
+
+ void Reset() {
+ Tags.shrink(0);
+ TextBuffer.Buf.shrink(0);
+ Size = 0;
+ }
+};
+
// Tick mark info
struct ImPlotTick
{
@@ -528,34 +542,29 @@ struct ImPlotTick
struct ImPlotTickCollection {
ImVector<ImPlotTick> Ticks;
ImGuiTextBuffer TextBuffer;
- float TotalWidthMax;
- float TotalWidth;
- float TotalHeight;
- float MaxWidth;
- float MaxHeight;
+ ImVec2 MaxSize;
+ ImVec2 LateSize;
int Size;
ImPlotTickCollection() { Reset(); }
const ImPlotTick& Append(const ImPlotTick& tick) {
if (tick.ShowLabel) {
- TotalWidth += tick.ShowLabel ? tick.LabelSize.x : 0;
- TotalHeight += tick.ShowLabel ? tick.LabelSize.y : 0;
- MaxWidth = tick.LabelSize.x > MaxWidth ? tick.LabelSize.x : MaxWidth;
- MaxHeight = tick.LabelSize.y > MaxHeight ? tick.LabelSize.y : MaxHeight;
+ MaxSize.x = tick.LabelSize.x > MaxSize.x ? tick.LabelSize.x : MaxSize.x;
+ MaxSize.y = tick.LabelSize.y > MaxSize.y ? tick.LabelSize.y : MaxSize.y;
}
Ticks.push_back(tick);
Size++;
return Ticks.back();
}
- const ImPlotTick& Append(double value, bool major, bool show_label, const char* fmt) {
+ const ImPlotTick& Append(double value, bool major, bool show_label, ImPlotFormatter formatter, void* data) {
ImPlotTick tick(value, major, show_label);
- if (show_label && fmt != NULL) {
- char temp[32];
+ if (show_label && formatter != NULL) {
+ char buff[IMPLOT_LABEL_MAX_SIZE];
tick.TextOffset = TextBuffer.size();
- snprintf(temp, 32, fmt, tick.PlotPos);
- TextBuffer.append(temp, temp + strlen(temp) + 1);
+ formatter(tick.PlotPos, buff, sizeof(buff), data);
+ TextBuffer.append(buff, buff + strlen(buff) + 1);
tick.LabelSize = ImGui::CalcTextSize(TextBuffer.Buf.Data + tick.TextOffset);
}
return Append(tick);
@@ -565,10 +574,21 @@ struct ImPlotTickCollection {
return TextBuffer.Buf.Data + Ticks[idx].TextOffset;
}
+ void OverrideSize(const ImVec2& size) {
+ MaxSize.x = size.x > MaxSize.x ? size.x : MaxSize.x;
+ MaxSize.y = size.y > MaxSize.y ? size.y : MaxSize.y;
+ }
+
+ void OverrideSizeLate(const ImVec2& size) {
+ LateSize.x = size.x > LateSize.x ? size.x : LateSize.x;
+ LateSize.y = size.y > LateSize.y ? size.y : LateSize.y;
+ }
+
void Reset() {
Ticks.shrink(0);
TextBuffer.Buf.shrink(0);
- TotalWidth = TotalHeight = MaxWidth = MaxHeight = 0;
+ MaxSize = LateSize;
+ LateSize = ImVec2(0,0);
Size = 0;
}
};
@@ -576,37 +596,71 @@ struct ImPlotTickCollection {
// Axis state information that must persist after EndPlot
struct ImPlotAxis
{
- ImPlotAxisFlags Flags;
- ImPlotAxisFlags PreviousFlags;
- ImPlotRange Range;
- float Pixels;
- ImPlotOrientation Orientation;
- bool Dragging;
- bool ExtHovered;
- bool AllHovered;
- bool Present;
- bool HasRange;
- double* LinkedMin;
- double* LinkedMax;
- ImPlotTime PickerTimeMin, PickerTimeMax;
- int PickerLevel;
- ImU32 ColorMaj, ColorMin, ColorTxt;
- ImGuiCond RangeCond;
- ImRect HoverRect;
+ ImGuiID ID;
+ ImPlotAxisFlags Flags;
+ ImPlotAxisFlags PreviousFlags;
+ ImPlotCond RangeCond;
+ ImPlotTickCollection Ticks;
+ ImPlotRange Range;
+ ImPlotRange FitExtents;
+ ImPlotAxis* OrthoAxis;
+ double* LinkedMin;
+ double* LinkedMax;
+ int PickerLevel;
+ ImPlotTime PickerTimeMin, PickerTimeMax;
+ float Datum1, Datum2;
+ float PixelMin, PixelMax;
+ double LinM, LogD;
+ ImRect HoverRect;
+ int LabelOffset;
+ ImU32 ColorMaj, ColorMin, ColorTick, ColorTxt, ColorBg, ColorHov, ColorAct, ColorHiLi;
+ char FormatSpec[16];
+ ImPlotFormatter Formatter;
+ void* FormatterData;
+ bool Enabled;
+ bool Vertical;
+ bool FitThisFrame;
+ bool HasRange;
+ bool HasFormatSpec;
+ bool ShowDefaultTicks;
+ bool Hovered;
+ bool Held;
ImPlotAxis() {
- Flags = PreviousFlags = ImPlotAxisFlags_None;
- Range.Min = 0;
- Range.Max = 1;
- Dragging = false;
- ExtHovered = false;
- AllHovered = false;
- LinkedMin = LinkedMax = NULL;
- PickerLevel = 0;
- ColorMaj = ColorMin = ColorTxt = 0;
+ Flags = PreviousFlags = ImPlotAxisFlags_None;
+ Range.Min = 0;
+ Range.Max = 1;
+ FitExtents.Min = HUGE_VAL;
+ FitExtents.Max = -HUGE_VAL;
+ OrthoAxis = NULL;
+ LinkedMin = LinkedMax = NULL;
+ PickerLevel = 0;
+ Datum1 = Datum2 = 0;
+ PixelMin = PixelMax = 0;
+ LabelOffset = -1;
+ ColorMaj = ColorMin = ColorTick = ColorTxt = ColorBg = ColorHov = ColorAct = 0;
+ ColorHiLi = IM_COL32_BLACK_TRANS;
+ Formatter = NULL;
+ FormatterData = NULL;
+ Enabled = Hovered = Held = FitThisFrame = HasRange = HasFormatSpec = false;
+ ShowDefaultTicks = true;
}
- bool SetMin(double _min, bool force=false) {
+ inline void Reset() {
+ Enabled = false;
+ LabelOffset = -1;
+ HasFormatSpec = false;
+ Formatter = NULL;
+ FormatterData = NULL;
+ ShowDefaultTicks = true;
+ FitThisFrame = false;
+ FitExtents.Min = HUGE_VAL;
+ FitExtents.Max = -HUGE_VAL;
+ OrthoAxis = NULL;
+ Ticks.Reset();
+ }
+
+ inline bool SetMin(double _min, bool force=false) {
if (!force && IsLockedMin())
return false;
_min = ImConstrainNan(ImConstrainInf(_min));
@@ -618,10 +672,11 @@ struct ImPlotAxis
return false;
Range.Min = _min;
PickerTimeMin = ImPlotTime::FromDouble(Range.Min);
+ UpdateTransformCache();
return true;
};
- bool SetMax(double _max, bool force=false) {
+ inline bool SetMax(double _max, bool force=false) {
if (!force && IsLockedMax())
return false;
_max = ImConstrainNan(ImConstrainInf(_max));
@@ -633,23 +688,25 @@ struct ImPlotAxis
return false;
Range.Max = _max;
PickerTimeMax = ImPlotTime::FromDouble(Range.Max);
+ UpdateTransformCache();
return true;
};
- void SetRange(double _min, double _max) {
- Range.Min = _min;
- Range.Max = _max;
+ inline void SetRange(double v1, double v2) {
+ Range.Min = ImMin(v1,v2);
+ Range.Max = ImMax(v1,v2);
Constrain();
PickerTimeMin = ImPlotTime::FromDouble(Range.Min);
PickerTimeMax = ImPlotTime::FromDouble(Range.Max);
+ UpdateTransformCache();
}
- void SetRange(const ImPlotRange& range) {
+ inline void SetRange(const ImPlotRange& range) {
SetRange(range.Min, range.Max);
}
- void SetAspect(double unit_per_pix) {
- double new_size = unit_per_pix * Pixels;
+ inline void SetAspect(double unit_per_pix) {
+ double new_size = unit_per_pix * PixelSize();
double delta = (new_size - Range.Size()) * 0.5f;
if (IsLocked())
return;
@@ -661,16 +718,18 @@ struct ImPlotAxis
SetRange(Range.Min - delta, Range.Max + delta);
}
- double GetAspect() const { return Range.Size() / Pixels; }
+ inline float PixelSize() const { return ImAbs(PixelMax - PixelMin); }
+
+ inline double GetAspect() const { return Range.Size() / PixelSize(); }
- void Constrain() {
+ inline void Constrain() {
Range.Min = ImConstrainNan(ImConstrainInf(Range.Min));
Range.Max = ImConstrainNan(ImConstrainInf(Range.Max));
- if (ImHasFlag(Flags, ImPlotAxisFlags_LogScale)) {
+ if (IsLog()) {
Range.Min = ImConstrainLog(Range.Min);
Range.Max = ImConstrainLog(Range.Max);
}
- if (ImHasFlag(Flags, ImPlotAxisFlags_Time)) {
+ if (IsTime()) {
Range.Min = ImConstrainTime(Range.Min);
Range.Max = ImConstrainTime(Range.Max);
}
@@ -678,22 +737,114 @@ struct ImPlotAxis
Range.Max = Range.Min + DBL_EPSILON;
}
- inline bool IsLabeled() const { return !ImHasFlag(Flags, ImPlotAxisFlags_NoTickLabels); }
- inline bool IsInverted() const { return ImHasFlag(Flags, ImPlotAxisFlags_Invert); }
+ inline void UpdateTransformCache() {
+ LinM = (PixelMax - PixelMin) / Range.Size();
+ LogD = IsLog() ? ImLog10(Range.Max / Range.Min) : 0;
+ }
+
+ inline double PixelsToPlot(float pix) const {
+ double plt = (pix - PixelMin) / LinM + Range.Min;
+ if (IsLog()) {
+ double t = (plt - Range.Min) / Range.Size();
+ plt = ImPow(10, t * LogD) * Range.Min;
+ }
+ return plt;
+ }
+
+ inline float PlotToPixels(double plt) const {
+ if (IsLog()) {
+ plt = plt <= 0.0 ? IMPLOT_LOG_ZERO : plt;
+ double t = ImLog10(plt / Range.Min) / LogD;
+ plt = ImLerp(Range.Min, Range.Max, (float)t);
+ }
+ return (float)(PixelMin + LinM * (plt - Range.Min));
+ }
+
+ inline void ExtendFit(double v) {
+ if (!ImNanOrInf(v) && !(IsLog() && v <= 0)) {
+ FitExtents.Min = v < FitExtents.Min ? v : FitExtents.Min;
+ FitExtents.Max = v > FitExtents.Max ? v : FitExtents.Max;
+ }
+ }
- inline bool IsAutoFitting() const { return ImHasFlag(Flags, ImPlotAxisFlags_AutoFit); }
- inline bool IsRangeLocked() const { return HasRange && RangeCond == ImGuiCond_Always; }
+ inline void ExtendFitWith(ImPlotAxis& alt, double v, double v_alt) {
+ if (ImHasFlag(Flags, ImPlotAxisFlags_RangeFit) && !alt.Range.Contains(v_alt))
+ return;
+ if (!ImNanOrInf(v) && !(IsLog() && v <= 0)) {
+ FitExtents.Min = v < FitExtents.Min ? v : FitExtents.Min;
+ FitExtents.Max = v > FitExtents.Max ? v : FitExtents.Max;
+ }
+ }
+
+ inline void ApplyFit(float padding) {
+ const double ext_size = FitExtents.Size() * 0.5;
+ FitExtents.Min -= ext_size * padding;
+ FitExtents.Max += ext_size * padding;
+ if (!IsLockedMin() && !ImNanOrInf(FitExtents.Min))
+ Range.Min = FitExtents.Min;
+ if (!IsLockedMax() && !ImNanOrInf(FitExtents.Max))
+ Range.Max = FitExtents.Max;
+ if (ImAlmostEqual(Range.Min, Range.Max)) {
+ Range.Max += 0.5;
+ Range.Min -= 0.5;
+ }
+ Constrain();
+ UpdateTransformCache();
+ }
- inline bool IsLockedMin() const { return !Present || IsRangeLocked() || ImHasFlag(Flags, ImPlotAxisFlags_LockMin); }
- inline bool IsLockedMax() const { return !Present || IsRangeLocked() || ImHasFlag(Flags, ImPlotAxisFlags_LockMax); }
- inline bool IsLocked() const { return IsLockedMin() && IsLockedMax(); }
+ inline bool HasLabel() const { return LabelOffset != -1 && !ImHasFlag(Flags, ImPlotAxisFlags_NoLabel); }
+ inline bool HasGridLines() const { return !ImHasFlag(Flags, ImPlotAxisFlags_NoGridLines); }
+ inline bool HasTickLabels() const { return !ImHasFlag(Flags, ImPlotAxisFlags_NoTickLabels); }
+ inline bool HasTickMarks() const { return !ImHasFlag(Flags, ImPlotAxisFlags_NoTickMarks); }
+ inline bool WillRender() const { return HasGridLines() || HasTickLabels() || HasTickMarks(); }
+ inline bool IsOpposite() const { return ImHasFlag(Flags, ImPlotAxisFlags_Opposite); }
+ inline bool IsInverted() const { return ImHasFlag(Flags, ImPlotAxisFlags_Invert); }
+ inline bool IsForeground() const { return ImHasFlag(Flags, ImPlotAxisFlags_Foreground); }
+ inline bool IsAutoFitting() const { return ImHasFlag(Flags, ImPlotAxisFlags_AutoFit); }
+ inline bool CanInitFit() const { return !ImHasFlag(Flags, ImPlotAxisFlags_NoInitialFit) && !HasRange && !LinkedMin && !LinkedMax; }
+ inline bool IsRangeLocked() const { return HasRange && RangeCond == ImPlotCond_Always; }
+ inline bool IsLockedMin() const { return !Enabled || IsRangeLocked() || ImHasFlag(Flags, ImPlotAxisFlags_LockMin); }
+ inline bool IsLockedMax() const { return !Enabled || IsRangeLocked() || ImHasFlag(Flags, ImPlotAxisFlags_LockMax); }
+ inline bool IsLocked() const { return IsLockedMin() && IsLockedMax(); }
+ inline bool IsInputLockedMin() const { return IsLockedMin() || IsAutoFitting(); }
+ inline bool IsInputLockedMax() const { return IsLockedMax() || IsAutoFitting(); }
+ inline bool IsInputLocked() const { return IsLocked() || IsAutoFitting(); }
+ inline bool IsTime() const { return ImHasFlag(Flags, ImPlotAxisFlags_Time); }
+ inline bool IsLog() const { return ImHasFlag(Flags, ImPlotAxisFlags_LogScale); }
+ inline bool HasMenus() const { return !ImHasFlag(Flags, ImPlotAxisFlags_NoMenus); }
- inline bool IsInputLockedMin() const { return IsLockedMin() || IsAutoFitting(); }
- inline bool IsInputLockedMax() const { return IsLockedMax() || IsAutoFitting(); }
- inline bool IsInputLocked() const { return IsLocked() || IsAutoFitting(); }
+ void PushLinks() {
+ if (LinkedMin) { *LinkedMin = Range.Min; }
+ if (LinkedMax) { *LinkedMax = Range.Max; }
+ }
- inline bool IsTime() const { return ImHasFlag(Flags, ImPlotAxisFlags_Time); }
- inline bool IsLog() const { return ImHasFlag(Flags, ImPlotAxisFlags_LogScale); }
+ void PullLinks() {
+ if (LinkedMin) { SetMin(*LinkedMin,true); }
+ if (LinkedMax) { SetMax(*LinkedMax,true); }
+ }
+};
+
+// Align plots group data
+struct ImPlotAlignmentData {
+ bool Vertical;
+ float PadA;
+ float PadB;
+ float PadAMax;
+ float PadBMax;
+ ImPlotAlignmentData() {
+ Vertical = true;
+ PadA = PadB = PadAMax = PadBMax = 0;
+ }
+ void Begin() { PadAMax = PadBMax = 0; }
+ void Update(float& pad_a, float& pad_b, float& delta_a, float& delta_b) {
+ float bak_a = pad_a; float bak_b = pad_b;
+ if (PadAMax < pad_a) { PadAMax = pad_a; }
+ if (PadBMax < pad_b) { PadBMax = pad_b; }
+ if (pad_a < PadA) { pad_a = PadA; delta_a = pad_a - bak_a; } else { delta_a = 0; }
+ if (pad_b < PadB) { pad_b = PadB; delta_b = pad_b - bak_b; } else { delta_b = 0; }
+ }
+ void End() { PadA = PadAMax; PadB = PadBMax; }
+ void Reset() { PadA = PadB = PadAMax = PadBMax = 0; }
};
// State information for Plot items
@@ -701,6 +852,7 @@ struct ImPlotItem
{
ImGuiID ID;
ImU32 Color;
+ ImRect LegendHoverRect;
int NameOffset;
bool Show;
bool LegendHovered;
@@ -717,109 +869,207 @@ struct ImPlotItem
~ImPlotItem() { ID = 0; }
};
-// Holds Legend state labels and item references
-struct ImPlotLegendData
+// Holds Legend state
+struct ImPlotLegend
{
- ImVector<int> Indices;
- ImGuiTextBuffer Labels;
+ ImPlotLegendFlags Flags;
+ ImPlotLegendFlags PreviousFlags;
+ ImPlotLocation Location;
+ ImPlotLocation PreviousLocation;
+ ImVector<int> Indices;
+ ImGuiTextBuffer Labels;
+ ImRect Rect;
+ bool Hovered;
+ bool Held;
+ bool CanGoInside;
+
+ ImPlotLegend() {
+ Flags = PreviousFlags = ImPlotLegendFlags_None;
+ CanGoInside = true;
+ Hovered = Held = false;
+ Location = ImPlotLocation_NorthWest;
+ }
+
void Reset() { Indices.shrink(0); Labels.Buf.shrink(0); }
};
-// Holds Plot state information that must persist after EndPlot
-struct ImPlotPlot
+// Holds Items and Legend data
+struct ImPlotItemGroup
{
ImGuiID ID;
- ImPlotFlags Flags;
- ImPlotFlags PreviousFlags;
- ImPlotAxis XAxis;
- ImPlotAxis YAxis[IMPLOT_Y_AXES];
- ImPlotLegendData LegendData;
- ImPool<ImPlotItem> Items;
- ImVec2 SelectStart;
- ImRect SelectRect;
- ImVec2 QueryStart;
- ImRect QueryRect;
- bool Initialized;
- bool Selecting;
- bool Selected;
- bool ContextLocked;
- bool Querying;
- bool Queried;
- bool DraggingQuery;
- bool LegendHovered;
- bool LegendOutside;
- bool LegendFlipSideNextFrame;
- bool FrameHovered;
- bool PlotHovered;
+ ImPlotLegend Legend;
+ ImPool<ImPlotItem> ItemPool;
int ColormapIdx;
- int CurrentYAxis;
- ImPlotLocation MousePosLocation;
- ImPlotLocation LegendLocation;
- ImPlotOrientation LegendOrientation;
- ImRect FrameRect;
- ImRect CanvasRect;
- ImRect PlotRect;
- ImRect AxesRect;
- ImRect LegendRect;
+
+ ImPlotItemGroup() { ColormapIdx = 0; }
+
+ int GetItemCount() const { return ItemPool.GetBufSize(); }
+ ImGuiID GetItemID(const char* label_id) { return ImGui::GetID(label_id); /* GetIDWithSeed */ }
+ ImPlotItem* GetItem(ImGuiID id) { return ItemPool.GetByKey(id); }
+ ImPlotItem* GetItem(const char* label_id) { return GetItem(GetItemID(label_id)); }
+ ImPlotItem* GetOrAddItem(ImGuiID id) { return ItemPool.GetOrAddByKey(id); }
+ ImPlotItem* GetItemByIndex(int i) { return ItemPool.GetByIndex(i); }
+ int GetItemIndex(ImPlotItem* item) { return ItemPool.GetIndex(item); }
+ int GetLegendCount() const { return Legend.Indices.size(); }
+ ImPlotItem* GetLegendItem(int i) { return ItemPool.GetByIndex(Legend.Indices[i]); }
+ const char* GetLegendLabel(int i) { return Legend.Labels.Buf.Data + GetLegendItem(i)->NameOffset; }
+ void Reset() { ItemPool.Clear(); Legend.Reset(); ColormapIdx = 0; }
+};
+
+// Holds Plot state information that must persist after EndPlot
+struct ImPlotPlot
+{
+ ImGuiID ID;
+ ImPlotFlags Flags;
+ ImPlotFlags PreviousFlags;
+ ImPlotLocation MouseTextLocation;
+ ImPlotMouseTextFlags MouseTextFlags;
+ ImPlotAxis Axes[ImAxis_COUNT];
+ ImGuiTextBuffer TextBuffer;
+ ImPlotItemGroup Items;
+ ImAxis CurrentX;
+ ImAxis CurrentY;
+ ImRect FrameRect;
+ ImRect CanvasRect;
+ ImRect PlotRect;
+ ImRect AxesRect;
+ ImRect SelectRect;
+ ImVec2 SelectStart;
+ int TitleOffset;
+ bool JustCreated;
+ bool Initialized;
+ bool SetupLocked;
+ bool FitThisFrame;
+ bool Hovered;
+ bool Held;
+ bool Selecting;
+ bool Selected;
+ bool ContextLocked;
ImPlotPlot() {
Flags = PreviousFlags = ImPlotFlags_None;
- XAxis.Orientation = ImPlotOrientation_Horizontal;
- for (int i = 0; i < IMPLOT_Y_AXES; ++i)
- YAxis[i].Orientation = ImPlotOrientation_Vertical;
- SelectStart = QueryStart = ImVec2(0,0);
- Initialized = Selecting = Selected = ContextLocked = Querying = Queried = DraggingQuery = LegendHovered = LegendOutside = LegendFlipSideNextFrame = false;
- ColormapIdx = CurrentYAxis = 0;
- LegendLocation = ImPlotLocation_North | ImPlotLocation_West;
- LegendOrientation = ImPlotOrientation_Vertical;
- MousePosLocation = ImPlotLocation_South | ImPlotLocation_East;
+ for (int i = 0; i < IMPLOT_NUM_X_AXES; ++i)
+ XAxis(i).Vertical = false;
+ for (int i = 0; i < IMPLOT_NUM_Y_AXES; ++i)
+ YAxis(i).Vertical = true;
+ SelectStart = ImVec2(0,0);
+ CurrentX = ImAxis_X1;
+ CurrentY = ImAxis_Y1;
+ MouseTextLocation = ImPlotLocation_South | ImPlotLocation_East;
+ MouseTextFlags = ImPlotMouseTextFlags_None;
+ TitleOffset = -1;
+ JustCreated = true;
+ Initialized = SetupLocked = FitThisFrame = false;
+ Hovered = Held = Selected = Selecting = ContextLocked = false;
+ }
+
+ inline bool IsInputLocked() const {
+ for (int i = 0; i < IMPLOT_NUM_X_AXES; ++i) {
+ if (!XAxis(i).IsInputLocked())
+ return false;
+ }
+ for (int i = 0; i < IMPLOT_NUM_Y_AXES; ++i) {
+ if (!YAxis(i).IsInputLocked())
+ return false;
+ }
+ return true;
+ }
+
+ inline void ClearTextBuffer() { TextBuffer.Buf.shrink(0); }
+
+ inline void SetTitle(const char* title) {
+ if (title && ImGui::FindRenderedTextEnd(title, NULL) != title) {
+ TitleOffset = TextBuffer.size();
+ TextBuffer.append(title, title + strlen(title) + 1);
+ }
+ else {
+ TitleOffset = -1;
+ }
+ }
+ inline bool HasTitle() const { return TitleOffset != -1 && !ImHasFlag(Flags, ImPlotFlags_NoTitle); }
+ inline const char* GetTitle() const { return TextBuffer.Buf.Data + TitleOffset; }
+
+ inline ImPlotAxis& XAxis(int i) { return Axes[ImAxis_X1 + i]; }
+ inline const ImPlotAxis& XAxis(int i) const { return Axes[ImAxis_X1 + i]; }
+ inline ImPlotAxis& YAxis(int i) { return Axes[ImAxis_Y1 + i]; }
+ inline const ImPlotAxis& YAxis(int i) const { return Axes[ImAxis_Y1 + i]; }
+
+ inline int EnabledAxesX() {
+ int cnt = 0;
+ for (int i = 0; i < IMPLOT_NUM_X_AXES; ++i)
+ cnt += XAxis(i).Enabled;
+ return cnt;
}
- int GetLegendCount() const { return LegendData.Indices.size(); }
- ImPlotItem* GetLegendItem(int i);
- const char* GetLegendLabel(int i);
+ inline int EnabledAxesY() {
+ int cnt = 0;
+ for (int i = 0; i < IMPLOT_NUM_Y_AXES; ++i)
+ cnt += YAxis(i).Enabled;
+ return cnt;
+ }
+
+ inline void SetAxisLabel(ImPlotAxis& axis, const char* label) {
+ if (label && ImGui::FindRenderedTextEnd(label, NULL) != label) {
+ axis.LabelOffset = TextBuffer.size();
+ TextBuffer.append(label, label + strlen(label) + 1);
+ }
+ else {
+ axis.LabelOffset = -1;
+ }
+ }
+
+ inline const char* GetAxisLabel(const ImPlotAxis& axis) const { return TextBuffer.Buf.Data + axis.LabelOffset; }
+};
- inline bool AnyYInputLocked() const { return YAxis[0].IsInputLocked() || (YAxis[1].Present ? YAxis[1].IsInputLocked() : false) || (YAxis[2].Present ? YAxis[2].IsInputLocked() : false); }
- inline bool AllYInputLocked() const { return YAxis[0].IsInputLocked() && (YAxis[1].Present ? YAxis[1].IsInputLocked() : true ) && (YAxis[2].Present ? YAxis[2].IsInputLocked() : true ); }
- inline bool IsInputLocked() const { return XAxis.IsInputLocked() && YAxis[0].IsInputLocked() && YAxis[1].IsInputLocked() && YAxis[2].IsInputLocked(); }
+// Holds subplot data that must persist afer EndSubplot
+struct ImPlotSubplot {
+ ImGuiID ID;
+ ImPlotSubplotFlags Flags;
+ ImPlotSubplotFlags PreviousFlags;
+ ImPlotItemGroup Items;
+ int Rows;
+ int Cols;
+ int CurrentIdx;
+ ImRect FrameRect;
+ ImRect GridRect;
+ ImVec2 CellSize;
+ ImVector<ImPlotAlignmentData> RowAlignmentData;
+ ImVector<ImPlotAlignmentData> ColAlignmentData;
+ ImVector<float> RowRatios;
+ ImVector<float> ColRatios;
+ ImVector<ImPlotRange> RowLinkData;
+ ImVector<ImPlotRange> ColLinkData;
+ float TempSizes[2];
+ bool FrameHovered;
+ bool HasTitle;
+
+ ImPlotSubplot() {
+ Rows = Cols = CurrentIdx = 0;
+ FrameHovered = false;
+ Items.Legend.Location = ImPlotLocation_North;
+ Items.Legend.Flags = ImPlotLegendFlags_Horizontal|ImPlotLegendFlags_Outside;
+ Items.Legend.CanGoInside = false;
+ HasTitle = false;
+ }
};
// Temporary data storage for upcoming plot
struct ImPlotNextPlotData
{
- ImGuiCond XRangeCond;
- ImGuiCond YRangeCond[IMPLOT_Y_AXES];
- ImPlotRange XRange;
- ImPlotRange YRange[IMPLOT_Y_AXES];
- bool HasXRange;
- bool HasYRange[IMPLOT_Y_AXES];
- bool ShowDefaultTicksX;
- bool ShowDefaultTicksY[IMPLOT_Y_AXES];
- char FmtX[16];
- char FmtY[IMPLOT_Y_AXES][16];
- bool HasFmtX;
- bool HasFmtY[IMPLOT_Y_AXES];
- bool FitX;
- bool FitY[IMPLOT_Y_AXES];
- double* LinkedXmin;
- double* LinkedXmax;
- double* LinkedYmin[IMPLOT_Y_AXES];
- double* LinkedYmax[IMPLOT_Y_AXES];
+ ImPlotCond RangeCond[ImAxis_COUNT];
+ ImPlotRange Range[ImAxis_COUNT];
+ bool HasRange[ImAxis_COUNT];
+ bool Fit[ImAxis_COUNT];
+ double* LinkedMin[ImAxis_COUNT];
+ double* LinkedMax[ImAxis_COUNT];
ImPlotNextPlotData() { Reset(); }
void Reset() {
- HasXRange = false;
- ShowDefaultTicksX = true;
- HasFmtX = false;
- FitX = false;
- LinkedXmin = LinkedXmax = NULL;
- for (int i = 0; i < IMPLOT_Y_AXES; ++i) {
- HasYRange[i] = false;
- ShowDefaultTicksY[i] = true;
- HasFmtY[i] = false;
- FitY[i] = false;
- LinkedYmin[i] = LinkedYmax[i] = NULL;
+ for (int i = 0; i < ImAxis_COUNT; ++i) {
+ HasRange[i] = false;
+ Fit[i] = false;
+ LinkedMin[i] = LinkedMax[i] = NULL;
}
}
@@ -843,7 +1093,7 @@ struct ImPlotNextItemData {
bool RenderMarkerFill;
bool HasHidden;
bool Hidden;
- ImGuiCond HiddenCond;
+ ImPlotCond HiddenCond;
ImPlotNextItemData() { Reset(); }
void Reset() {
for (int i = 0; i < 5; ++i)
@@ -857,40 +1107,22 @@ struct ImPlotNextItemData {
// Holds state information that must persist between calls to BeginPlot()/EndPlot()
struct ImPlotContext {
// Plot States
- ImPool<ImPlotPlot> Plots;
- ImPlotPlot* CurrentPlot;
- ImPlotItem* CurrentItem;
- ImPlotItem* PreviousItem;
+ ImPool<ImPlotPlot> Plots;
+ ImPool<ImPlotSubplot> Subplots;
+ ImPlotPlot* CurrentPlot;
+ ImPlotSubplot* CurrentSubplot;
+ ImPlotItemGroup* CurrentItems;
+ ImPlotItem* CurrentItem;
+ ImPlotItem* PreviousItem;
// Tick Marks and Labels
ImPlotTickCollection CTicks;
- ImPlotTickCollection XTicks;
- ImPlotTickCollection YTicks[IMPLOT_Y_AXES];
- float YAxisReference[IMPLOT_Y_AXES];
- // Annotation and User Labels
+ // Annotation and Tabs
ImPlotAnnotationCollection Annotations;
+ ImPlotTagCollection Tags;
- // Transformations and Data Extents
- ImPlotScale Scales[IMPLOT_Y_AXES];
- ImRect PixelRange[IMPLOT_Y_AXES];
- double Mx;
- double My[IMPLOT_Y_AXES];
- double LogDenX;
- double LogDenY[IMPLOT_Y_AXES];
- ImPlotRange ExtentsX;
- ImPlotRange ExtentsY[IMPLOT_Y_AXES];
-
- // Data Fitting Flags
- bool FitThisFrame;
- bool FitX;
- bool FitY[IMPLOT_Y_AXES];
-
- // Axis Rendering Flags
- bool RenderX;
- bool RenderY[IMPLOT_Y_AXES];
-
- // Axis Locking Flags
+ // Flags
bool ChildWindowMade;
// Style and Colormaps
@@ -904,16 +1136,22 @@ struct ImPlotContext {
tm Tm;
// Temp data for general use
- ImVector<double> Temp1, Temp2;
+ ImVector<double> TempDouble1, TempDouble2;
+ ImVector<int> TempInt1;
// Misc
- int VisibleItemCount;
int DigitalPlotItemCnt;
int DigitalPlotOffset;
ImPlotNextPlotData NextPlotData;
ImPlotNextItemData NextItemData;
ImPlotInputMap InputMap;
- ImPlotPoint MousePos[IMPLOT_Y_AXES];
+ bool OpenContextThisFrame;
+ ImGuiTextBuffer MousePosStringBuilder;
+
+ // Align plots
+ ImPool<ImPlotAlignmentData> AlignmentData;
+ ImPlotAlignmentData* CurrentAlignmentH;
+ ImPlotAlignmentData* CurrentAlignmentV;
};
//-----------------------------------------------------------------------------
@@ -930,14 +1168,11 @@ namespace ImPlot {
// Initializes an ImPlotContext
IMPLOT_API void Initialize(ImPlotContext* ctx);
// Resets an ImPlot context for the next call to BeginPlot
-IMPLOT_API void Reset(ImPlotContext* ctx);
-
-//-----------------------------------------------------------------------------
-// [SECTION] Input Utils
-//-----------------------------------------------------------------------------
-
-// Allows changing how keyboard/mouse interaction works.
-IMPLOT_API ImPlotInputMap& GetInputMap();
+IMPLOT_API void ResetCtxForNextPlot(ImPlotContext* ctx);
+// Resets an ImPlot context for the next call to BeginAlignedPlots
+IMPLOT_API void ResetCtxForNextAlignedPlots(ImPlotContext* ctx);
+// Resets an ImPlot context for the next call to BeginSubplot
+IMPLOT_API void ResetCtxForNextSubplot(ImPlotContext* ctx);
//-----------------------------------------------------------------------------
// [SECTION] Plot Utils
@@ -954,6 +1189,27 @@ IMPLOT_API void BustPlotCache();
IMPLOT_API void ShowPlotContextMenu(ImPlotPlot& plot);
//-----------------------------------------------------------------------------
+// [SECTION] Setup Utils
+//-----------------------------------------------------------------------------
+
+// Lock Setup and call SetupFinish if necessary.
+static inline void SetupLock() {
+ if (!GImPlot->CurrentPlot->SetupLocked)
+ SetupFinish();
+ GImPlot->CurrentPlot->SetupLocked = true;
+}
+
+//-----------------------------------------------------------------------------
+// [SECTION] Subplot Utils
+//-----------------------------------------------------------------------------
+
+// Advances to next subplot
+IMPLOT_API void SubplotNextCell();
+
+// Shows a subplot's context menu.
+IMPLOT_API void ShowSubplotsContextMenu(ImPlotSubplot& subplot);
+
+//-----------------------------------------------------------------------------
// [SECTION] Item Utils
//-----------------------------------------------------------------------------
@@ -975,66 +1231,90 @@ IMPLOT_API void BustItemCache();
// [SECTION] Axis Utils
//-----------------------------------------------------------------------------
-// Gets the current y-axis for the current plot
-static inline int GetCurrentYAxis() { return GImPlot->CurrentPlot->CurrentYAxis; }
-// Updates axis ticks, lins, and label colors
-IMPLOT_API void UpdateAxisColors(int axis_flag, ImPlotAxis* axis);
+// Returns true if any enabled axis is locked from user input.
+static inline bool AnyAxesInputLocked(ImPlotAxis* axes, int count) {
+ for (int i = 0; i < count; ++i) {
+ if (axes[i].Enabled && axes[i].IsInputLocked())
+ return true;
+ }
+ return false;
+}
-// Updates plot-to-pixel space transformation variables for the current plot.
-IMPLOT_API void UpdateTransformCache();
-// Gets the XY scale for the current plot and y-axis
-static inline ImPlotScale GetCurrentScale() { return GImPlot->Scales[GetCurrentYAxis()]; }
+// Returns true if all enabled axes are locked from user input.
+static inline bool AllAxesInputLocked(ImPlotAxis* axes, int count) {
+ for (int i = 0; i < count; ++i) {
+ if (axes[i].Enabled && !axes[i].IsInputLocked())
+ return false;
+ }
+ return true;
+}
-// Returns true if the user has requested data to be fit.
-static inline bool FitThisFrame() { return GImPlot->FitThisFrame; }
-// Extend the the extents of an axis on current plot so that it encompes v
-static inline void FitPointAxis(ImPlotAxis& axis, ImPlotRange& ext, double v) {
- if (!ImNanOrInf(v) && !(ImHasFlag(axis.Flags, ImPlotAxisFlags_LogScale) && v <= 0)) {
- ext.Min = v < ext.Min ? v : ext.Min;
- ext.Max = v > ext.Max ? v : ext.Max;
+static inline bool AnyAxesHeld(ImPlotAxis* axes, int count) {
+ for (int i = 0; i < count; ++i) {
+ if (axes[i].Enabled && axes[i].Held)
+ return true;
}
+ return false;
}
-// Extend the the extents of an axis on current plot so that it encompes v
-static inline void FitPointMultiAxis(ImPlotAxis& axis, ImPlotAxis& alt, ImPlotRange& ext, double v, double v_alt) {
- if (ImHasFlag(axis.Flags, ImPlotAxisFlags_RangeFit) && !alt.Range.Contains(v_alt))
- return;
- if (!ImNanOrInf(v) && !(ImHasFlag(axis.Flags, ImPlotAxisFlags_LogScale) && v <= 0)) {
- ext.Min = v < ext.Min ? v : ext.Min;
- ext.Max = v > ext.Max ? v : ext.Max;
+
+static inline bool AnyAxesHovered(ImPlotAxis* axes, int count) {
+ for (int i = 0; i < count; ++i) {
+ if (axes[i].Enabled && axes[i].Hovered)
+ return true;
}
+ return false;
+}
+
+// Gets the XY scale for the current plot and y-axis (TODO)
+static inline ImPlotScale GetCurrentScale() {
+ ImPlotPlot& plot = *GetCurrentPlot();
+ ImPlotAxis& x = plot.Axes[plot.CurrentX];
+ ImPlotAxis& y = plot.Axes[plot.CurrentY];
+ if (!x.IsLog() && !y.IsLog())
+ return ImPlotScale_LinLin;
+ else if (x.IsLog() && !y.IsLog())
+ return ImPlotScale_LogLin;
+ else if (!x.IsLog() && y.IsLog())
+ return ImPlotScale_LinLog;
+ else
+ return ImPlotScale_LogLog;
+}
+
+// Returns true if the user has requested data to be fit.
+static inline bool FitThisFrame() {
+ return GImPlot->CurrentPlot->FitThisFrame;
}
+
// Extends the current plot's axes so that it encompasses a vertical line at x
static inline void FitPointX(double x) {
- FitPointAxis(GImPlot->CurrentPlot->XAxis, GImPlot->ExtentsX, x);
+ ImPlotPlot& plot = *GetCurrentPlot();
+ ImPlotAxis& x_axis = plot.Axes[plot.CurrentX];
+ x_axis.ExtendFit(x);
}
+
// Extends the current plot's axes so that it encompasses a horizontal line at y
static inline void FitPointY(double y) {
- const ImPlotYAxis y_axis = GImPlot->CurrentPlot->CurrentYAxis;
- FitPointAxis(GImPlot->CurrentPlot->YAxis[y_axis], GImPlot->ExtentsY[y_axis], y);
+ ImPlotPlot& plot = *GetCurrentPlot();
+ ImPlotAxis& y_axis = plot.Axes[plot.CurrentY];
+ y_axis.ExtendFit(y);
}
+
// Extends the current plot's axes so that it encompasses point p
static inline void FitPoint(const ImPlotPoint& p) {
- const ImPlotYAxis y_axis = GImPlot->CurrentPlot->CurrentYAxis;
- FitPointMultiAxis(GImPlot->CurrentPlot->XAxis, GImPlot->CurrentPlot->YAxis[y_axis], GImPlot->ExtentsX, p.x, p.y);
- FitPointMultiAxis(GImPlot->CurrentPlot->YAxis[y_axis], GImPlot->CurrentPlot->XAxis, GImPlot->ExtentsY[y_axis], p.y, p.x);
+ ImPlotPlot& plot = *GetCurrentPlot();
+ ImPlotAxis& x_axis = plot.Axes[plot.CurrentX];
+ ImPlotAxis& y_axis = plot.Axes[plot.CurrentY];
+ x_axis.ExtendFitWith(y_axis, p.x, p.y);
+ y_axis.ExtendFitWith(x_axis, p.y, p.x);
}
// Returns true if two ranges overlap
static inline bool RangesOverlap(const ImPlotRange& r1, const ImPlotRange& r2)
{ return r1.Min <= r2.Max && r2.Min <= r1.Max; }
-// Updates pointers for linked axes from axis internal range.
-IMPLOT_API void PushLinkedAxis(ImPlotAxis& axis);
-// Updates axis internal range from points for linked axes.
-IMPLOT_API void PullLinkedAxis(ImPlotAxis& axis);
-
// Shows an axis's context menu.
IMPLOT_API void ShowAxisContextMenu(ImPlotAxis& axis, ImPlotAxis* equal_axis, bool time_allowed = false);
-// Get format spec for axis
-static inline const char* GetFormatX() { return GImPlot->NextPlotData.HasFmtX ? GImPlot->NextPlotData.FmtX : IMPLOT_LABEL_FMT; }
-static inline const char* GetFormatY(ImPlotYAxis y) { return GImPlot->NextPlotData.HasFmtY[y] ? GImPlot->NextPlotData.FmtY[y] : IMPLOT_LABEL_FMT; }
-
//-----------------------------------------------------------------------------
// [SECTION] Legend Utils
//-----------------------------------------------------------------------------
@@ -1042,11 +1322,13 @@ static inline const char* GetFormatY(ImPlotYAxis y) { return GImPlot->NextPlotDa
// Gets the position of an inner rect that is located inside of an outer rect according to an ImPlotLocation and padding amount.
IMPLOT_API ImVec2 GetLocationPos(const ImRect& outer_rect, const ImVec2& inner_size, ImPlotLocation location, const ImVec2& pad = ImVec2(0,0));
// Calculates the bounding box size of a legend
-IMPLOT_API ImVec2 CalcLegendSize(ImPlotPlot& plot, const ImVec2& pad, const ImVec2& spacing, ImPlotOrientation orientation);
+IMPLOT_API ImVec2 CalcLegendSize(ImPlotItemGroup& items, const ImVec2& pad, const ImVec2& spacing, bool vertical);
// Renders legend entries into a bounding box
-IMPLOT_API void ShowLegendEntries(ImPlotPlot& plot, const ImRect& legend_bb, bool interactable, const ImVec2& pad, const ImVec2& spacing, ImPlotOrientation orientation, ImDrawList& DrawList);
+IMPLOT_API bool ShowLegendEntries(ImPlotItemGroup& items, const ImRect& legend_bb, bool interactable, const ImVec2& pad, const ImVec2& spacing, bool vertical, ImDrawList& DrawList);
// Shows an alternate legend for the plot identified by #title_id, outside of the plot frame (can be called before or after of Begin/EndPlot but must occur in the same ImGui window!).
-IMPLOT_API void ShowAltLegend(const char* title_id, ImPlotOrientation orientation = ImPlotOrientation_Vertical, const ImVec2 size = ImVec2(0,0), bool interactable = true);
+IMPLOT_API void ShowAltLegend(const char* title_id, bool vertical = true, const ImVec2 size = ImVec2(0,0), bool interactable = true);
+// Shows an legends's context menu.
+IMPLOT_API bool ShowLegendContextMenu(ImPlotLegend& legend, bool visible);
//-----------------------------------------------------------------------------
// [SECTION] Tick Utils
@@ -1056,16 +1338,16 @@ IMPLOT_API void ShowAltLegend(const char* title_id, ImPlotOrientation orientatio
IMPLOT_API void LabelTickTime(ImPlotTick& tick, ImGuiTextBuffer& buffer, const ImPlotTime& t, ImPlotDateTimeFmt fmt);
// Populates a list of ImPlotTicks with normal spaced and formatted ticks
-IMPLOT_API void AddTicksDefault(const ImPlotRange& range, float pix, ImPlotOrientation orn, ImPlotTickCollection& ticks, const char* fmt);
+IMPLOT_API void AddTicksDefault(const ImPlotRange& range, float pix, bool vertical, ImPlotTickCollection& ticks, ImPlotFormatter formatter, void* data);
// Populates a list of ImPlotTicks with logarithmic space and formatted ticks
-IMPLOT_API void AddTicksLogarithmic(const ImPlotRange& range, float pix, ImPlotOrientation orn, ImPlotTickCollection& ticks, const char* fmt);
+IMPLOT_API void AddTicksLogarithmic(const ImPlotRange& range, float pix, bool vertical, ImPlotTickCollection& ticks, ImPlotFormatter formatter, void* data);
+// Populates a list of ImPlotTicks with custom spaced and labeled ticks
+IMPLOT_API void AddTicksCustom(const double* values, const char* const labels[], int n, ImPlotTickCollection& ticks, ImPlotFormatter formatter, void* data);
// Populates a list of ImPlotTicks with time formatted ticks.
IMPLOT_API void AddTicksTime(const ImPlotRange& range, float plot_width, ImPlotTickCollection& ticks);
-// Populates a list of ImPlotTicks with custom spaced and labeled ticks
-IMPLOT_API void AddTicksCustom(const double* values, const char* const labels[], int n, ImPlotTickCollection& ticks, const char* fmt);
// Create a a string label for a an axis value
-IMPLOT_API int LabelAxisValue(const ImPlotAxis& axis, const ImPlotTickCollection& ticks, double value, char* buff, int size);
+IMPLOT_API void LabelAxisValue(const ImPlotAxis& axis, double value, char* buff, int size, bool round = false);
//-----------------------------------------------------------------------------
// [SECTION] Styling Utils
@@ -1087,13 +1369,15 @@ static inline ImU32 GetStyleColorU32(ImPlotCol idx) { return ImGui::ColorConve
// Draws vertical text. The position is the bottom left of the text rect.
IMPLOT_API void AddTextVertical(ImDrawList *DrawList, ImVec2 pos, ImU32 col, const char* text_begin, const char* text_end = NULL);
+// Draws multiline horizontal text centered.
+IMPLOT_API void AddTextCentered(ImDrawList* DrawList, ImVec2 top_center, ImU32 col, const char* text_begin, const char* text_end = NULL);
// Calculates the size of vertical text
static inline ImVec2 CalcTextSizeVertical(const char *text) {
ImVec2 sz = ImGui::CalcTextSize(text);
return ImVec2(sz.y, sz.x);
}
// Returns white or black text given background color
-static inline ImU32 CalcTextColor(const ImVec4& bg) { return (bg.x * 0.299 + bg.y * 0.587 + bg.z * 0.114) > 0.5 ? IM_COL32_BLACK : IM_COL32_WHITE; }
+static inline ImU32 CalcTextColor(const ImVec4& bg) { return (bg.x * 0.299f + bg.y * 0.587f + bg.z * 0.114f) > 0.5f ? IM_COL32_BLACK : IM_COL32_WHITE; }
static inline ImU32 CalcTextColor(ImU32 bg) { return CalcTextColor(ImGui::ColorConvertU32ToFloat4(bg)); }
// Lightens or darkens a color for hover
static inline ImU32 CalcHoverColor(ImU32 col) { return ImMixU32(col, CalcTextColor(col), 32); }
@@ -1149,13 +1433,6 @@ void FillRange(ImVector<T>& buffer, int n, T vmin, T vmax) {
}
}
-// Offsets and strides a data buffer
-template <typename T>
-static inline T OffsetAndStride(const T* data, int idx, int count, int offset, int stride) {
- idx = ImPosMod(offset + idx, count);
- return *(const T*)(const void*)((const unsigned char*)data + (size_t)idx * stride);
-}
-
// Calculate histogram bin counts and widths
template <typename T>
static inline void CalculateBins(const T* values, int count, ImPlotBin meth, const ImPlotRange& range, int& bins_out, double& width_out) {
diff --git a/3rdparty/implot/implot_items.cpp b/3rdparty/implot/implot_items.cpp
index 9f94492..ae750c9 100644
--- a/3rdparty/implot/implot_items.cpp
+++ b/3rdparty/implot/implot_items.cpp
@@ -20,29 +20,44 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
-// ImPlot v0.10 WIP
+// ImPlot v0.13 WIP
#include "implot.h"
#include "implot_internal.h"
-#ifdef _MSC_VER
-#define sprintf sprintf_s
-#endif
-
#define SQRT_1_2 0.70710678118f
#define SQRT_3_2 0.86602540378f
-#define IMPLOT_NORMALIZE2F_OVER_ZERO(VX, VY) \
- { \
- float d2 = VX * VX + VY * VY; \
- if (d2 > 0.0f) { \
- float inv_len = 1.0f / ImSqrt(d2); \
- VX *= inv_len; \
- VY *= inv_len; \
- } \
- }
+#ifndef IMPLOT_NO_FORCE_INLINE
+ #ifdef _MSC_VER
+ #define IMPLOT_INLINE __forceinline
+ #elif defined(__GNUC__)
+ #define IMPLOT_INLINE inline __attribute__((__always_inline__))
+ #elif defined(__CLANG__)
+ #if __has_attribute(__always_inline__)
+ #define IMPLOT_INLINE inline __attribute__((__always_inline__))
+ #else
+ #define IMPLOT_INLINE inline
+ #endif
+ #else
+ #define IMPLOT_INLINE inline
+ #endif
+#else
+ #define IMPLOT_INLINE inline
+#endif
+
+#if defined __SSE__ || defined __x86_64__ || defined _M_X64
+#ifndef IMGUI_ENABLE_SSE
+#include <immintrin.h>
+#endif
+static IMPLOT_INLINE float ImInvSqrt(float x) { return _mm_cvtss_f32(_mm_rsqrt_ss(_mm_set_ss(x))); }
+#else
+static IMPLOT_INLINE float ImInvSqrt(float x) { return 1.0f / sqrtf(x); }
+#endif
-// Support for pre-1.82 version. Users on 1.82+ can use 0 (default) flags to mean "all corners" but in order to support older versions we are more explicit.
+#define IMPLOT_NORMALIZE2F_OVER_ZERO(VX,VY) do { float d2 = VX*VX + VY*VY; if (d2 > 0.0f) { float inv_len = ImInvSqrt(d2); VX *= inv_len; VY *= inv_len; } } while (0)
+
+// Support for pre-1.82 versions. Users on 1.82+ can use 0 (default) flags to mean "all corners" but in order to support older versions we are more explicit.
#if (IMGUI_VERSION_NUM < 18102) && !defined(ImDrawFlags_RoundCornersAll)
#define ImDrawFlags_RoundCornersAll ImDrawCornerFlags_All
#endif
@@ -50,37 +65,50 @@
namespace ImPlot {
//-----------------------------------------------------------------------------
+// Utils
+//-----------------------------------------------------------------------------
+
+// Calc maximum index size of ImDrawIdx
+template <typename T>
+struct MaxIdx { static const unsigned int Value; };
+template <> const unsigned int MaxIdx<unsigned short>::Value = 65535;
+template <> const unsigned int MaxIdx<unsigned int>::Value = 4294967295;
+
+//-----------------------------------------------------------------------------
// Item Utils
//-----------------------------------------------------------------------------
ImPlotItem* RegisterOrGetItem(const char* label_id, bool* just_created) {
ImPlotContext& gp = *GImPlot;
- ImGuiID id = ImGui::GetID(label_id);
+ ImPlotItemGroup& Items = *gp.CurrentItems;
+ ImGuiID id = Items.GetItemID(label_id);
if (just_created != NULL)
- *just_created = gp.CurrentPlot->Items.GetByKey(id) == NULL;
- ImPlotItem* item = gp.CurrentPlot->Items.GetOrAddByKey(id);
+ *just_created = Items.GetItem(id) == NULL;
+ ImPlotItem* item = Items.GetOrAddItem(id);
if (item->SeenThisFrame)
return item;
item->SeenThisFrame = true;
- int idx = gp.CurrentPlot->Items.GetIndex(item);
+ int idx = Items.GetItemIndex(item);
item->ID = id;
if (ImGui::FindRenderedTextEnd(label_id, NULL) != label_id) {
- gp.CurrentPlot->LegendData.Indices.push_back(idx);
- item->NameOffset = gp.CurrentPlot->LegendData.Labels.size();
- gp.CurrentPlot->LegendData.Labels.append(label_id, label_id + strlen(label_id) + 1);
+ Items.Legend.Indices.push_back(idx);
+ item->NameOffset = Items.Legend.Labels.size();
+ Items.Legend.Labels.append(label_id, label_id + strlen(label_id) + 1);
}
else {
item->Show = true;
}
- if (item->Show)
- gp.VisibleItemCount++;
return item;
}
ImPlotItem* GetItem(const char* label_id) {
ImPlotContext& gp = *GImPlot;
- ImGuiID id = ImGui::GetID(label_id);
- return gp.CurrentPlot->Items.GetByKey(id);
+ return gp.CurrentItems->GetItem(label_id);
+}
+
+bool IsItemHidden(const char* label_id) {
+ ImPlotItem* item = GetItem(label_id);
+ return item != NULL && !item->Show;
}
ImPlotItem* GetCurrentItem() {
@@ -123,20 +151,15 @@ ImVec4 GetLastItemColor() {
return ImVec4();
}
-void HideNextItem(bool hidden, ImGuiCond cond) {
- ImPlotContext& gp = *GImPlot;
- gp.NextItemData.HasHidden = true;
- gp.NextItemData.Hidden = hidden;
- gp.NextItemData.HiddenCond = cond;
-}
-
void BustItemCache() {
ImPlotContext& gp = *GImPlot;
- for (int p = 0; p < gp.Plots.GetSize(); ++p) {
+ for (int p = 0; p < gp.Plots.GetBufSize(); ++p) {
ImPlotPlot& plot = *gp.Plots.GetByIndex(p);
- plot.ColormapIdx = 0;
- plot.Items.Clear();
- plot.LegendData.Reset();
+ plot.Items.Reset();
+ }
+ for (int p = 0; p < gp.Subplots.GetBufSize(); ++p) {
+ ImPlotSubplot& subplot = *gp.Subplots.GetByIndex(p);
+ subplot.Items.Reset();
}
}
@@ -146,12 +169,15 @@ void BustColorCache(const char* plot_title_id) {
BustItemCache();
}
else {
- ImPlotPlot* plot = gp.Plots.GetByKey(ImGui::GetCurrentWindow()->GetID(plot_title_id));
- if (plot == NULL)
- return;
- plot->ColormapIdx = 0;
- plot->Items.Clear();
- plot->LegendData.Reset();
+ ImGuiID id = ImGui::GetCurrentWindow()->GetID(plot_title_id);
+ ImPlotPlot* plot = gp.Plots.GetByKey(id);
+ if (plot != NULL)
+ plot->Items.Reset();
+ else {
+ ImPlotSubplot* subplot = gp.Subplots.GetByKey(id);
+ if (subplot != NULL)
+ subplot->Items.Reset();
+ }
}
}
@@ -159,10 +185,15 @@ void BustColorCache(const char* plot_title_id) {
// Begin/EndItem
//-----------------------------------------------------------------------------
+static const float ITEM_HIGHLIGHT_LINE_SCALE = 2.0f;
+static const float ITEM_HIGHLIGHT_MARK_SCALE = 1.25f;
+
+
// Begins a new item. Returns false if the item should not be plotted.
bool BeginItem(const char* label_id, ImPlotCol recolor_from) {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "PlotX() needs to be called between BeginPlot() and EndPlot()!");
+ SetupLock();
bool just_created;
ImPlotItem* item = RegisterOrGetItem(label_id, &just_created);
// set current item
@@ -212,12 +243,21 @@ bool BeginItem(const char* label_id, ImPlotCol recolor_from) {
s.DigitalBitGap = s.DigitalBitGap < 0 ? gp.Style.DigitalBitGap : s.DigitalBitGap;
// apply alpha modifier(s)
s.Colors[ImPlotCol_Fill].w *= s.FillAlpha;
- // s.Colors[ImPlotCol_MarkerFill].w *= s.FillAlpha; // TODO: this should be separate, if it at all
+ s.Colors[ImPlotCol_MarkerFill].w *= s.FillAlpha; // TODO: this should be separate, if it at all
// apply highlight mods
- if (item->LegendHovered && !ImHasFlag(gp.CurrentPlot->Flags, ImPlotFlags_NoHighlight)) {
- s.LineWeight *= 2;
- s.MarkerWeight *= 2;
- // TODO: highlight fills?
+ if (item->LegendHovered) {
+ if (!ImHasFlag(gp.CurrentItems->Legend.Flags, ImPlotLegendFlags_NoHighlightItem)) {
+ s.LineWeight *= ITEM_HIGHLIGHT_LINE_SCALE;
+ s.MarkerSize *= ITEM_HIGHLIGHT_MARK_SCALE;
+ s.MarkerWeight *= ITEM_HIGHLIGHT_LINE_SCALE;
+ // TODO: how to highlight fills?
+ }
+ if (!ImHasFlag(gp.CurrentItems->Legend.Flags, ImPlotLegendFlags_NoHighlightAxis)) {
+ if (gp.CurrentPlot->EnabledAxesX() > 1)
+ gp.CurrentPlot->Axes[gp.CurrentPlot->CurrentX].ColorHiLi = item->Color;
+ if (gp.CurrentPlot->EnabledAxesY() > 1)
+ gp.CurrentPlot->Axes[gp.CurrentPlot->CurrentY].ColorHiLi = item->Color;
+ }
}
// set render flags
s.RenderLine = s.Colors[ImPlotCol_Line].w > 0 && s.LineWeight > 0;
@@ -243,141 +283,133 @@ void EndItem() {
}
//-----------------------------------------------------------------------------
+// INDEXERS
+//-----------------------------------------------------------------------------
+
+// Offsets and strides a data buffer
+template <typename T>
+IMPLOT_INLINE T IndexData(const T* data, int idx, int count, int offset, int stride) {
+ const int s = ((offset == 0) << 0) | ((stride == sizeof(T)) << 1);
+ switch (s) {
+ case 3 : return data[idx];
+ case 2 : return data[(offset + idx) % count];
+ case 1 : return *(const T*)(const void*)((const unsigned char*)data + (size_t)((idx) ) * stride);
+ case 0 : return *(const T*)(const void*)((const unsigned char*)data + (size_t)((offset + idx) % count) * stride);
+ default: return T(0);
+ }
+}
+
+//-----------------------------------------------------------------------------
// GETTERS
//-----------------------------------------------------------------------------
// Getters can be thought of as iterators that convert user data (e.g. raw arrays)
// to ImPlotPoints
-// Interprets an array of Y points as ImPlotPoints where the X value is the index
template <typename T>
-struct GetterYs {
- GetterYs(const T* ys, int count, double xscale, double x0, int offset, int stride) :
- Ys(ys),
+struct GetterIdx {
+ GetterIdx(const T* data, int count, int offset = 0, int stride = sizeof(T)) :
+ Data(data),
Count(count),
- XScale(xscale),
- X0(x0),
Offset(count ? ImPosMod(offset, count) : 0),
Stride(stride)
{ }
- inline ImPlotPoint operator()(int idx) const {
- return ImPlotPoint(X0 + XScale * idx, (double)OffsetAndStride(Ys, idx, Count, Offset, Stride));
+ template <typename I> IMPLOT_INLINE double operator()(I idx) const {
+ return (double)IndexData(Data, idx, Count, Offset, Stride);
}
- const T* const Ys;
- const int Count;
- const double XScale;
- const double X0;
- const int Offset;
- const int Stride;
+ const T* Data;
+ int Count;
+ int Offset;
+ int Stride;
};
-// Interprets separate arrays for X and Y points as ImPlotPoints
-template <typename T>
-struct GetterXsYs {
- GetterXsYs(const T* xs, const T* ys, int count, int offset, int stride) :
- Xs(xs),
- Ys(ys),
- Count(count),
- Offset(count ? ImPosMod(offset, count) : 0),
- Stride(stride)
- { }
- inline ImPlotPoint operator()(int idx) const {
- return ImPlotPoint((double)OffsetAndStride(Xs, idx, Count, Offset, Stride), (double)OffsetAndStride(Ys, idx, Count, Offset, Stride));
+struct GetterLin {
+ GetterLin(double m, double b) : M(m), B(b) { }
+ template <typename I> IMPLOT_INLINE double operator()(I idx) const {
+ return M * idx + B;
}
- const T* const Xs;
- const T* const Ys;
- const int Count;
- const int Offset;
- const int Stride;
+ const double M;
+ const double B;
};
-// Always returns a constant Y reference value where the X value is the index
-struct GetterYRef {
- GetterYRef(double y_ref, int count, double xscale, double x0) :
- YRef(y_ref),
- Count(count),
- XScale(xscale),
- X0(x0)
- { }
- inline ImPlotPoint operator()(int idx) const {
- return ImPlotPoint(X0 + XScale*idx, YRef);
- }
- const double YRef;
- const int Count;
- const double XScale;
- const double X0;
+struct GetterRef {
+ GetterRef(double ref) : Ref(ref) { }
+ template <typename I> IMPLOT_INLINE double operator()(I) const { return Ref; }
+ const double Ref;
};
-// Interprets an array of X points as ImPlotPoints where the Y value is a constant reference value
-template <typename T>
-struct GetterXsYRef {
- GetterXsYRef(const T* xs, double y_ref, int count, int offset, int stride) :
- Xs(xs),
- YRef(y_ref),
- Count(count),
- Offset(count ? ImPosMod(offset, count) : 0),
- Stride(stride)
- { }
- inline ImPlotPoint operator()(int idx) const {
- return ImPlotPoint((double)OffsetAndStride(Xs, idx, Count, Offset, Stride), YRef);
+template <typename TGetterX, typename TGetterY>
+struct GetterXY {
+ GetterXY(TGetterX x, TGetterY y, int count) : GetterX(x), GetterY(y), Count(count) { }
+ template <typename I> IMPLOT_INLINE ImPlotPoint operator()(I idx) const {
+ return ImPlotPoint(GetterX(idx),GetterY(idx));
}
- const T* const Xs;
- const double YRef;
+ const TGetterX GetterX;
+ const TGetterY GetterY;
const int Count;
- const int Offset;
- const int Stride;
};
-// Interprets an array of Y points as ImPlotPoints where the X value is a constant reference value
+// Interprets an array of Y points as ImPlotPoints where the X value is the index
template <typename T>
-struct GetterXRefYs {
- GetterXRefYs(double x_ref, const T* ys, int count, int offset, int stride) :
- XRef(x_ref),
- Ys(ys),
+struct GetterXs {
+ GetterXs(const T* xs, int count, double yscale, double y0, int offset, int stride) :
+ Xs(xs),
Count(count),
+ YScale(yscale),
+ Y0(y0),
Offset(count ? ImPosMod(offset, count) : 0),
Stride(stride)
{ }
- inline ImPlotPoint operator()(int idx) const {
- return ImPlotPoint(XRef, (double)OffsetAndStride(Ys, idx, Count, Offset, Stride));
+ template <typename I> IMPLOT_INLINE ImPlotPoint operator()(I idx) const {
+ return ImPlotPoint((double)IndexData(Xs, idx, Count, Offset, Stride), Y0 + YScale * idx);
}
- const double XRef;
- const T* const Ys;
+ const T* const Xs;
const int Count;
+ const double YScale;
+ const double Y0;
const int Offset;
const int Stride;
};
/// Interprets a user's function pointer as ImPlotPoints
struct GetterFuncPtr {
- GetterFuncPtr(ImPlotPoint (*getter)(void* data, int idx), void* data, int count, int offset) :
+ GetterFuncPtr(ImPlotPoint (*getter)(void* data, int idx), void* data, int count) :
Getter(getter),
Data(data),
- Count(count),
- Offset(count ? ImPosMod(offset, count) : 0)
+ Count(count)
{ }
- inline ImPlotPoint operator()(int idx) const {
- idx = ImPosMod(Offset + idx, Count);
+ template <typename I> IMPLOT_INLINE ImPlotPoint operator()(I idx) const {
return Getter(Data, idx);
}
ImPlotPoint (* const Getter)(void* data, int idx);
void* const Data;
const int Count;
- const int Offset;
};
-template <typename T>
-struct GetterBarV {
- const T* Ys; double XShift; int Count; int Offset; int Stride;
- GetterBarV(const T* ys, double xshift, int count, int offset, int stride) { Ys = ys; XShift = xshift; Count = count; Offset = offset; Stride = stride; }
- inline ImPlotPoint operator()(int idx) const { return ImPlotPoint((double)idx + (double)XShift, (double)OffsetAndStride(Ys, idx, Count, Offset, Stride)); }
+template <typename TGetter>
+struct GetterOverrideX {
+ GetterOverrideX(const TGetter& getter, double x) : Getter(getter), X(x), Count(getter.Count) { }
+ template <typename I> IMPLOT_INLINE ImPlotPoint operator()(I idx) const {
+ ImPlotPoint p = Getter(idx);
+ p.x = X;
+ return p;
+ }
+ const TGetter& Getter;
+ const double X;
+ const int Count;
};
-template <typename T>
-struct GetterBarH {
- const T* Xs; double YShift; int Count; int Offset; int Stride;
- GetterBarH(const T* xs, double yshift, int count, int offset, int stride) { Xs = xs; YShift = yshift; Count = count; Offset = offset; Stride = stride; }
- inline ImPlotPoint operator()(int idx) const { return ImPlotPoint((double)OffsetAndStride(Xs, idx, Count, Offset, Stride), (double)idx + (double)YShift); }
+template <typename TGetter>
+struct GetterOverrideY {
+ GetterOverrideY(const TGetter& getter, double y) : Getter(getter), Y(y), Count(getter.Count) { }
+ template <typename I> IMPLOT_INLINE ImPlotPoint operator()(I idx) const {
+ ImPlotPoint p = Getter(idx);
+ p.y = Y;
+ return p;
+ }
+ const TGetter& Getter;
+ const double Y;
+ const int Count;
};
template <typename T>
@@ -391,11 +423,11 @@ struct GetterError {
Offset(count ? ImPosMod(offset, count) : 0),
Stride(stride)
{ }
- inline ImPlotPointError operator()(int idx) const {
- return ImPlotPointError((double)OffsetAndStride(Xs, idx, Count, Offset, Stride),
- (double)OffsetAndStride(Ys, idx, Count, Offset, Stride),
- (double)OffsetAndStride(Neg, idx, Count, Offset, Stride),
- (double)OffsetAndStride(Pos, idx, Count, Offset, Stride));
+ template <typename I> IMPLOT_INLINE ImPlotPointError operator()(I idx) const {
+ return ImPlotPointError((double)IndexData(Xs, idx, Count, Offset, Stride),
+ (double)IndexData(Ys, idx, Count, Offset, Stride),
+ (double)IndexData(Neg, idx, Count, Offset, Stride),
+ (double)IndexData(Pos, idx, Count, Offset, Stride));
}
const T* const Xs;
const T* const Ys;
@@ -412,69 +444,71 @@ struct GetterError {
// Transforms convert points in plot space (i.e. ImPlotPoint) to pixel space (i.e. ImVec2)
-// Transforms points for linear x and linear y space
-struct TransformerLinLin {
- TransformerLinLin() : YAxis(GetCurrentYAxis()) {}
- // inline ImVec2 operator()(const ImPlotPoint& plt) const { return (*this)(plt.x, plt.y); }
- inline ImVec2 operator()(const ImPlotPoint& plt) const {
- ImPlotContext& gp = *GImPlot;
- return ImVec2( (float)(gp.PixelRange[YAxis].Min.x + gp.Mx * (plt.x - gp.CurrentPlot->XAxis.Range.Min)),
- (float)(gp.PixelRange[YAxis].Min.y + gp.My[YAxis] * (plt.y - gp.CurrentPlot->YAxis[YAxis].Range.Min)) );
- }
- const int YAxis;
+struct TransformerLin {
+ TransformerLin(double pixMin, double pltMin, double, double m, double ) : PixMin(pixMin), PltMin(pltMin), M(m) { }
+ template <typename T> IMPLOT_INLINE float operator()(T p) const { return (float)(PixMin + M * (p - PltMin)); }
+ double PixMin, PltMin, M;
};
-// Transforms points for log x and linear y space
-struct TransformerLogLin {
- TransformerLogLin() : YAxis(GetCurrentYAxis()) {}
- inline ImVec2 operator()(const ImPlotPoint& plt) const {
- ImPlotContext& gp = *GImPlot;
- double t = ImLog10(plt.x / gp.CurrentPlot->XAxis.Range.Min) / gp.LogDenX;
- double x = ImLerp(gp.CurrentPlot->XAxis.Range.Min, gp.CurrentPlot->XAxis.Range.Max, (float)t);
- return ImVec2( (float)(gp.PixelRange[YAxis].Min.x + gp.Mx * (x - gp.CurrentPlot->XAxis.Range.Min)),
- (float)(gp.PixelRange[YAxis].Min.y + gp.My[YAxis] * (plt.y - gp.CurrentPlot->YAxis[YAxis].Range.Min)) );
+struct TransformerLog {
+ TransformerLog(double pixMin, double pltMin, double pltMax, double m, double den) : Den(den), PltMin(pltMin), PltMax(pltMax), PixMin(pixMin), M(m) { }
+ template <typename T> IMPLOT_INLINE float operator()(T p) const {
+ p = p <= 0.0 ? IMPLOT_LOG_ZERO : p;
+ double t = ImLog10(p / PltMin) / Den;
+ p = ImLerp(PltMin, PltMax, (float)t);
+ return (float)(PixMin + M * (p - PltMin));
}
- const int YAxis;
+ double Den, PltMin, PltMax, PixMin, M;
};
-// Transforms points for linear x and log y space
-struct TransformerLinLog {
- TransformerLinLog() : YAxis(GetCurrentYAxis()) {}
- inline ImVec2 operator()(const ImPlotPoint& plt) const {
- ImPlotContext& gp = *GImPlot;
- double t = ImLog10(plt.y / gp.CurrentPlot->YAxis[YAxis].Range.Min) / gp.LogDenY[YAxis];
- double y = ImLerp(gp.CurrentPlot->YAxis[YAxis].Range.Min, gp.CurrentPlot->YAxis[YAxis].Range.Max, (float)t);
- return ImVec2( (float)(gp.PixelRange[YAxis].Min.x + gp.Mx * (plt.x - gp.CurrentPlot->XAxis.Range.Min)),
- (float)(gp.PixelRange[YAxis].Min.y + gp.My[YAxis] * (y - gp.CurrentPlot->YAxis[YAxis].Range.Min)) );
- }
- const int YAxis;
-};
+template <typename TransformerX, typename TransformerY>
+struct TransformerXY {
+ TransformerXY(const ImPlotAxis& x_axis, const ImPlotAxis& y_axis) :
+ Tx(x_axis.PixelMin,
+ x_axis.Range.Min,
+ x_axis.Range.Max,
+ x_axis.LinM,
+ x_axis.LogD),
+ Ty(y_axis.PixelMin,
+ y_axis.Range.Min,
+ y_axis.Range.Max,
+ y_axis.LinM,
+ y_axis.LogD)
+ { }
-// Transforms points for log x and log y space
-struct TransformerLogLog {
- TransformerLogLog() : YAxis(GetCurrentYAxis()) {}
- inline ImVec2 operator()(const ImPlotPoint& plt) const {
- ImPlotContext& gp = *GImPlot;
- double t = ImLog10(plt.x / gp.CurrentPlot->XAxis.Range.Min) / gp.LogDenX;
- double x = ImLerp(gp.CurrentPlot->XAxis.Range.Min, gp.CurrentPlot->XAxis.Range.Max, (float)t);
- t = ImLog10(plt.y / gp.CurrentPlot->YAxis[YAxis].Range.Min) / gp.LogDenY[YAxis];
- double y = ImLerp(gp.CurrentPlot->YAxis[YAxis].Range.Min, gp.CurrentPlot->YAxis[YAxis].Range.Max, (float)t);
- return ImVec2( (float)(gp.PixelRange[YAxis].Min.x + gp.Mx * (x - gp.CurrentPlot->XAxis.Range.Min)),
- (float)(gp.PixelRange[YAxis].Min.y + gp.My[YAxis] * (y - gp.CurrentPlot->YAxis[YAxis].Range.Min)) );
+ TransformerXY(const ImPlotPlot& plot) :
+ TransformerXY(plot.Axes[plot.CurrentX], plot.Axes[plot.CurrentY])
+ { }
+
+ TransformerXY() :
+ TransformerXY(*GImPlot->CurrentPlot)
+ { }
+
+ template <typename P> IMPLOT_INLINE ImVec2 operator()(const P& plt) const {
+ ImVec2 out;
+ out.x = Tx(plt.x);
+ out.y = Ty(plt.y);
+ return out;
}
- const int YAxis;
+ TransformerX Tx;
+ TransformerY Ty;
};
+typedef TransformerXY<TransformerLin,TransformerLin> TransformerLinLin;
+typedef TransformerXY<TransformerLin,TransformerLog> TransformerLinLog;
+typedef TransformerXY<TransformerLog,TransformerLin> TransformerLogLin;
+typedef TransformerXY<TransformerLog,TransformerLog> TransformerLogLog;
+
//-----------------------------------------------------------------------------
// PRIMITIVE RENDERERS
//-----------------------------------------------------------------------------
-inline void AddLine(const ImVec2& P1, const ImVec2& P2, float weight, ImU32 col, ImDrawList& DrawList, ImVec2 uv) {
+IMPLOT_INLINE void PrimLine(const ImVec2& P1, const ImVec2& P2, float half_weight, ImU32 col, ImDrawList& DrawList, ImVec2 uv) {
float dx = P2.x - P1.x;
float dy = P2.y - P1.y;
IMPLOT_NORMALIZE2F_OVER_ZERO(dx, dy);
- dx *= (weight * 0.5f);
- dy *= (weight * 0.5f);
+ dx *= half_weight;
+ dy *= half_weight;
DrawList._VtxWritePtr[0].pos.x = P1.x + dy;
DrawList._VtxWritePtr[0].pos.y = P1.y - dx;
DrawList._VtxWritePtr[0].uv = uv;
@@ -502,7 +536,7 @@ inline void AddLine(const ImVec2& P1, const ImVec2& P2, float weight, ImU32 col,
DrawList._VtxCurrentIdx += 4;
}
-inline void AddRectFilled(const ImVec2& Pmin, const ImVec2& Pmax, ImU32 col, ImDrawList& DrawList, ImVec2 uv) {
+IMPLOT_INLINE void PrimRectFilled(const ImVec2& Pmin, const ImVec2& Pmax, ImU32 col, ImDrawList& DrawList, ImVec2 uv) {
DrawList._VtxWritePtr[0].pos = Pmin;
DrawList._VtxWritePtr[0].uv = uv;
DrawList._VtxWritePtr[0].col = col;
@@ -530,22 +564,22 @@ inline void AddRectFilled(const ImVec2& Pmin, const ImVec2& Pmax, ImU32 col, ImD
template <typename TGetter, typename TTransformer>
struct LineStripRenderer {
- inline LineStripRenderer(const TGetter& getter, const TTransformer& transformer, ImU32 col, float weight) :
+ IMPLOT_INLINE LineStripRenderer(const TGetter& getter, const TTransformer& transformer, ImU32 col, float weight) :
Getter(getter),
Transformer(transformer),
Prims(Getter.Count - 1),
Col(col),
- Weight(weight)
+ HalfWeight(weight/2)
{
P1 = Transformer(Getter(0));
}
- inline bool operator()(ImDrawList& DrawList, const ImRect& cull_rect, const ImVec2& uv, int prim) const {
+ IMPLOT_INLINE bool operator()(ImDrawList& DrawList, const ImRect& cull_rect, const ImVec2& uv, int prim) const {
ImVec2 P2 = Transformer(Getter(prim + 1));
if (!cull_rect.Overlaps(ImRect(ImMin(P1, P2), ImMax(P1, P2)))) {
P1 = P2;
return false;
}
- AddLine(P1,P2,Weight,Col,DrawList,uv);
+ PrimLine(P1,P2,HalfWeight,Col,DrawList,uv);
P1 = P2;
return true;
}
@@ -553,15 +587,43 @@ struct LineStripRenderer {
const TTransformer& Transformer;
const int Prims;
const ImU32 Col;
- const float Weight;
+ const float HalfWeight;
mutable ImVec2 P1;
static const int IdxConsumed = 6;
static const int VtxConsumed = 4;
};
+template <typename TGetter1, typename TGetter2, typename TTransformer>
+struct LineSegmentsRenderer {
+ IMPLOT_INLINE LineSegmentsRenderer(const TGetter1& getter1, const TGetter2& getter2, const TTransformer& transformer, ImU32 col, float weight) :
+ Getter1(getter1),
+ Getter2(getter2),
+ Transformer(transformer),
+ Prims(ImMin(Getter1.Count, Getter2.Count)),
+ Col(col),
+ HalfWeight(weight/2)
+ {}
+ IMPLOT_INLINE bool operator()(ImDrawList& DrawList, const ImRect& cull_rect, const ImVec2& uv, int prim) const {
+ ImVec2 P1 = Transformer(Getter1(prim));
+ ImVec2 P2 = Transformer(Getter2(prim));
+ if (!cull_rect.Overlaps(ImRect(ImMin(P1, P2), ImMax(P1, P2))))
+ return false;
+ PrimLine(P1,P2,HalfWeight,Col,DrawList,uv);
+ return true;
+ }
+ const TGetter1& Getter1;
+ const TGetter2& Getter2;
+ const TTransformer& Transformer;
+ const int Prims;
+ const ImU32 Col;
+ const float HalfWeight;
+ static const int IdxConsumed = 6;
+ static const int VtxConsumed = 4;
+};
+
template <typename TGetter, typename TTransformer>
struct StairsRenderer {
- inline StairsRenderer(const TGetter& getter, const TTransformer& transformer, ImU32 col, float weight) :
+ IMPLOT_INLINE StairsRenderer(const TGetter& getter, const TTransformer& transformer, ImU32 col, float weight) :
Getter(getter),
Transformer(transformer),
Prims(Getter.Count - 1),
@@ -570,17 +632,14 @@ struct StairsRenderer {
{
P1 = Transformer(Getter(0));
}
- inline bool operator()(ImDrawList& DrawList, const ImRect& cull_rect, const ImVec2& uv, int prim) const {
+ IMPLOT_INLINE bool operator()(ImDrawList& DrawList, const ImRect& cull_rect, const ImVec2& uv, int prim) const {
ImVec2 P2 = Transformer(Getter(prim + 1));
if (!cull_rect.Overlaps(ImRect(ImMin(P1, P2), ImMax(P1, P2)))) {
P1 = P2;
return false;
}
- AddRectFilled(ImVec2(P1.x, P1.y + HalfWeight), ImVec2(P2.x, P1.y - HalfWeight), Col, DrawList, uv);
- AddRectFilled(ImVec2(P2.x - HalfWeight, P2.y), ImVec2(P2.x + HalfWeight, P1.y), Col, DrawList, uv);
-
- // AddLine(P1, P12, Weight, Col, DrawList, uv);
- // AddLine(P12, P2, Weight, Col, DrawList, uv);
+ PrimRectFilled(ImVec2(P1.x, P1.y + HalfWeight), ImVec2(P2.x, P1.y - HalfWeight), Col, DrawList, uv);
+ PrimRectFilled(ImVec2(P2.x - HalfWeight, P2.y), ImVec2(P2.x + HalfWeight, P1.y), Col, DrawList, uv);
P1 = P2;
return true;
}
@@ -594,37 +653,11 @@ struct StairsRenderer {
static const int VtxConsumed = 8;
};
-template <typename TGetter1, typename TGetter2, typename TTransformer>
-struct LineSegmentsRenderer {
- inline LineSegmentsRenderer(const TGetter1& getter1, const TGetter2& getter2, const TTransformer& transformer, ImU32 col, float weight) :
- Getter1(getter1),
- Getter2(getter2),
- Transformer(transformer),
- Prims(ImMin(Getter1.Count, Getter2.Count)),
- Col(col),
- Weight(weight)
- {}
- inline bool operator()(ImDrawList& DrawList, const ImRect& cull_rect, const ImVec2& uv, int prim) const {
- ImVec2 P1 = Transformer(Getter1(prim));
- ImVec2 P2 = Transformer(Getter2(prim));
- if (!cull_rect.Overlaps(ImRect(ImMin(P1, P2), ImMax(P1, P2))))
- return false;
- AddLine(P1,P2,Weight,Col,DrawList,uv);
- return true;
- }
- const TGetter1& Getter1;
- const TGetter2& Getter2;
- const TTransformer& Transformer;
- const int Prims;
- const ImU32 Col;
- const float Weight;
- static const int IdxConsumed = 6;
- static const int VtxConsumed = 4;
-};
+
template <typename TGetter1, typename TGetter2, typename TTransformer>
struct ShadedRenderer {
- ShadedRenderer(const TGetter1& getter1, const TGetter2& getter2, const TTransformer& transformer, ImU32 col) :
+ IMPLOT_INLINE ShadedRenderer(const TGetter1& getter1, const TGetter2& getter2, const TTransformer& transformer, ImU32 col) :
Getter1(getter1),
Getter2(getter2),
Transformer(transformer),
@@ -635,7 +668,7 @@ struct ShadedRenderer {
P12 = Transformer(Getter2(0));
}
- inline bool operator()(ImDrawList& DrawList, const ImRect& cull_rect, const ImVec2& uv, int prim) const {
+ IMPLOT_INLINE bool operator()(ImDrawList& DrawList, const ImRect& cull_rect, const ImVec2& uv, int prim) const {
ImVec2 P21 = Transformer(Getter1(prim+1));
ImVec2 P22 = Transformer(Getter2(prim+1));
ImRect rect(ImMin(ImMin(ImMin(P11,P12),P21),P22), ImMax(ImMax(ImMax(P11,P12),P21),P22));
@@ -666,8 +699,8 @@ struct ShadedRenderer {
DrawList._IdxWritePtr[1] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 1 + intersect);
DrawList._IdxWritePtr[2] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 3);
DrawList._IdxWritePtr[3] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 1);
- DrawList._IdxWritePtr[4] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 3 - intersect);
- DrawList._IdxWritePtr[5] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 4);
+ DrawList._IdxWritePtr[4] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 4);
+ DrawList._IdxWritePtr[5] = (ImDrawIdx)(DrawList._VtxCurrentIdx + 3 - intersect);
DrawList._IdxWritePtr += 6;
DrawList._VtxCurrentIdx += 5;
P11 = P21;
@@ -685,15 +718,9 @@ struct ShadedRenderer {
static const int VtxConsumed = 5;
};
-// Stupid way of calculating maximum index size of ImDrawIdx without integer overflow issues
-template <typename T>
-struct MaxIdx { static const unsigned int Value; };
-template <> const unsigned int MaxIdx<unsigned short>::Value = 65535;
-template <> const unsigned int MaxIdx<unsigned int>::Value = 4294967295;
-
/// Renders primitive shapes in bulk as efficiently as possible.
template <typename Renderer>
-inline void RenderPrimitives(const Renderer& renderer, ImDrawList& DrawList, const ImRect& cull_rect) {
+IMPLOT_INLINE void RenderPrimitives(const Renderer& renderer, ImDrawList& DrawList, const ImRect& cull_rect) {
unsigned int prims = renderer.Prims;
unsigned int prims_culled = 0;
unsigned int idx = 0;
@@ -730,7 +757,7 @@ inline void RenderPrimitives(const Renderer& renderer, ImDrawList& DrawList, con
}
template <typename Getter, typename Transformer>
-inline void RenderLineStrip(const Getter& getter, const Transformer& transformer, ImDrawList& DrawList, float line_weight, ImU32 col) {
+IMPLOT_INLINE void RenderLineStrip(const Getter& getter, const Transformer& transformer, ImDrawList& DrawList, float line_weight, ImU32 col) {
ImPlotContext& gp = *GImPlot;
if (ImHasFlag(gp.CurrentPlot->Flags, ImPlotFlags_AntiAliased) || gp.Style.AntiAliasedLines) {
ImVec2 p1 = transformer(getter(0));
@@ -747,7 +774,7 @@ inline void RenderLineStrip(const Getter& getter, const Transformer& transformer
}
template <typename Getter1, typename Getter2, typename Transformer>
-inline void RenderLineSegments(const Getter1& getter1, const Getter2& getter2, const Transformer& transformer, ImDrawList& DrawList, float line_weight, ImU32 col) {
+IMPLOT_INLINE void RenderLineSegments(const Getter1& getter1, const Getter2& getter2, const Transformer& transformer, ImDrawList& DrawList, float line_weight, ImU32 col) {
ImPlotContext& gp = *GImPlot;
if (ImHasFlag(gp.CurrentPlot->Flags, ImPlotFlags_AntiAliased) || gp.Style.AntiAliasedLines) {
int I = ImMin(getter1.Count, getter2.Count);
@@ -764,7 +791,7 @@ inline void RenderLineSegments(const Getter1& getter1, const Getter2& getter2, c
}
template <typename Getter, typename Transformer>
-inline void RenderStairs(const Getter& getter, const Transformer& transformer, ImDrawList& DrawList, float line_weight, ImU32 col) {
+IMPLOT_INLINE void RenderStairs(const Getter& getter, const Transformer& transformer, ImDrawList& DrawList, float line_weight, ImU32 col) {
ImPlotContext& gp = *GImPlot;
if (ImHasFlag(gp.CurrentPlot->Flags, ImPlotFlags_AntiAliased) || gp.Style.AntiAliasedLines) {
ImVec2 p1 = transformer(getter(0));
@@ -787,14 +814,14 @@ inline void RenderStairs(const Getter& getter, const Transformer& transformer, I
// MARKER RENDERERS
//-----------------------------------------------------------------------------
-inline void TransformMarker(ImVec2* points, int n, const ImVec2& c, float s) {
+IMPLOT_INLINE void TransformMarker(ImVec2* points, int n, const ImVec2& c, float s) {
for (int i = 0; i < n; ++i) {
points[i].x = c.x + points[i].x * s;
points[i].y = c.y + points[i].y * s;
}
}
-inline void RenderMarkerGeneral(ImDrawList& DrawList, ImVec2* points, int n, const ImVec2& c, float s, bool outline, ImU32 col_outline, bool fill, ImU32 col_fill, float weight) {
+IMPLOT_INLINE void RenderMarkerGeneral(ImDrawList& DrawList, ImVec2* points, int n, const ImVec2& c, float s, bool outline, ImU32 col_outline, bool fill, ImU32 col_fill, float weight) {
TransformMarker(points, n, c, s);
if (fill)
DrawList.AddConvexPolyFilled(points, n, col_fill);
@@ -804,7 +831,7 @@ inline void RenderMarkerGeneral(ImDrawList& DrawList, ImVec2* points, int n, con
}
}
-inline void RenderMarkerCircle(ImDrawList& DrawList, const ImVec2& c, float s, bool outline, ImU32 col_outline, bool fill, ImU32 col_fill, float weight) {
+IMPLOT_INLINE void RenderMarkerCircle(ImDrawList& DrawList, const ImVec2& c, float s, bool outline, ImU32 col_outline, bool fill, ImU32 col_fill, float weight) {
ImVec2 marker[10] = {ImVec2(1.0f, 0.0f),
ImVec2(0.809017f, 0.58778524f),
ImVec2(0.30901697f, 0.95105654f),
@@ -818,37 +845,37 @@ inline void RenderMarkerCircle(ImDrawList& DrawList, const ImVec2& c, float s, b
RenderMarkerGeneral(DrawList, marker, 10, c, s, outline, col_outline, fill, col_fill, weight);
}
-inline void RenderMarkerDiamond(ImDrawList& DrawList, const ImVec2& c, float s, bool outline, ImU32 col_outline, bool fill, ImU32 col_fill, float weight) {
+IMPLOT_INLINE void RenderMarkerDiamond(ImDrawList& DrawList, const ImVec2& c, float s, bool outline, ImU32 col_outline, bool fill, ImU32 col_fill, float weight) {
ImVec2 marker[4] = {ImVec2(1, 0), ImVec2(0, -1), ImVec2(-1, 0), ImVec2(0, 1)};
RenderMarkerGeneral(DrawList, marker, 4, c, s, outline, col_outline, fill, col_fill, weight);
}
-inline void RenderMarkerSquare(ImDrawList& DrawList, const ImVec2& c, float s, bool outline, ImU32 col_outline, bool fill, ImU32 col_fill, float weight) {
+IMPLOT_INLINE void RenderMarkerSquare(ImDrawList& DrawList, const ImVec2& c, float s, bool outline, ImU32 col_outline, bool fill, ImU32 col_fill, float weight) {
ImVec2 marker[4] = {ImVec2(SQRT_1_2,SQRT_1_2),ImVec2(SQRT_1_2,-SQRT_1_2),ImVec2(-SQRT_1_2,-SQRT_1_2),ImVec2(-SQRT_1_2,SQRT_1_2)};
RenderMarkerGeneral(DrawList, marker, 4, c, s, outline, col_outline, fill, col_fill, weight);
}
-inline void RenderMarkerUp(ImDrawList& DrawList, const ImVec2& c, float s, bool outline, ImU32 col_outline, bool fill, ImU32 col_fill, float weight) {
+IMPLOT_INLINE void RenderMarkerUp(ImDrawList& DrawList, const ImVec2& c, float s, bool outline, ImU32 col_outline, bool fill, ImU32 col_fill, float weight) {
ImVec2 marker[3] = {ImVec2(SQRT_3_2,0.5f),ImVec2(0,-1),ImVec2(-SQRT_3_2,0.5f)};
RenderMarkerGeneral(DrawList, marker, 3, c, s, outline, col_outline, fill, col_fill, weight);
}
-inline void RenderMarkerDown(ImDrawList& DrawList, const ImVec2& c, float s, bool outline, ImU32 col_outline, bool fill, ImU32 col_fill, float weight) {
+IMPLOT_INLINE void RenderMarkerDown(ImDrawList& DrawList, const ImVec2& c, float s, bool outline, ImU32 col_outline, bool fill, ImU32 col_fill, float weight) {
ImVec2 marker[3] = {ImVec2(SQRT_3_2,-0.5f),ImVec2(0,1),ImVec2(-SQRT_3_2,-0.5f)};
RenderMarkerGeneral(DrawList, marker, 3, c, s, outline, col_outline, fill, col_fill, weight);
}
-inline void RenderMarkerLeft(ImDrawList& DrawList, const ImVec2& c, float s, bool outline, ImU32 col_outline, bool fill, ImU32 col_fill, float weight) {
+IMPLOT_INLINE void RenderMarkerLeft(ImDrawList& DrawList, const ImVec2& c, float s, bool outline, ImU32 col_outline, bool fill, ImU32 col_fill, float weight) {
ImVec2 marker[3] = {ImVec2(-1,0), ImVec2(0.5, SQRT_3_2), ImVec2(0.5, -SQRT_3_2)};
RenderMarkerGeneral(DrawList, marker, 3, c, s, outline, col_outline, fill, col_fill, weight);
}
-inline void RenderMarkerRight(ImDrawList& DrawList, const ImVec2& c, float s, bool outline, ImU32 col_outline, bool fill, ImU32 col_fill, float weight) {
+IMPLOT_INLINE void RenderMarkerRight(ImDrawList& DrawList, const ImVec2& c, float s, bool outline, ImU32 col_outline, bool fill, ImU32 col_fill, float weight) {
ImVec2 marker[3] = {ImVec2(1,0), ImVec2(-0.5, SQRT_3_2), ImVec2(-0.5, -SQRT_3_2)};
RenderMarkerGeneral(DrawList, marker, 3, c, s, outline, col_outline, fill, col_fill, weight);
}
-inline void RenderMarkerAsterisk(ImDrawList& DrawList, const ImVec2& c, float s, bool /*outline*/, ImU32 col_outline, bool /*fill*/, ImU32 /*col_fill*/, float weight) {
+IMPLOT_INLINE void RenderMarkerAsterisk(ImDrawList& DrawList, const ImVec2& c, float s, bool /*outline*/, ImU32 col_outline, bool /*fill*/, ImU32 /*col_fill*/, float weight) {
ImVec2 marker[6] = {ImVec2(SQRT_3_2, 0.5f), ImVec2(0, -1), ImVec2(-SQRT_3_2, 0.5f), ImVec2(SQRT_3_2, -0.5f), ImVec2(0, 1), ImVec2(-SQRT_3_2, -0.5f)};
TransformMarker(marker, 6, c, s);
DrawList.AddLine(marker[0], marker[5], col_outline, weight);
@@ -856,14 +883,14 @@ inline void RenderMarkerAsterisk(ImDrawList& DrawList, const ImVec2& c, float s,
DrawList.AddLine(marker[2], marker[3], col_outline, weight);
}
-inline void RenderMarkerPlus(ImDrawList& DrawList, const ImVec2& c, float s, bool /*outline*/, ImU32 col_outline, bool /*fill*/, ImU32 /*col_fill*/, float weight) {
+IMPLOT_INLINE void RenderMarkerPlus(ImDrawList& DrawList, const ImVec2& c, float s, bool /*outline*/, ImU32 col_outline, bool /*fill*/, ImU32 /*col_fill*/, float weight) {
ImVec2 marker[4] = {ImVec2(1, 0), ImVec2(0, -1), ImVec2(-1, 0), ImVec2(0, 1)};
TransformMarker(marker, 4, c, s);
DrawList.AddLine(marker[0], marker[2], col_outline, weight);
DrawList.AddLine(marker[1], marker[3], col_outline, weight);
}
-inline void RenderMarkerCross(ImDrawList& DrawList, const ImVec2& c, float s, bool /*outline*/, ImU32 col_outline, bool /*fill*/, ImU32 /*col_fill*/, float weight) {
+IMPLOT_INLINE void RenderMarkerCross(ImDrawList& DrawList, const ImVec2& c, float s, bool /*outline*/, ImU32 col_outline, bool /*fill*/, ImU32 /*col_fill*/, float weight) {
ImVec2 marker[4] = {ImVec2(SQRT_1_2,SQRT_1_2),ImVec2(SQRT_1_2,-SQRT_1_2),ImVec2(-SQRT_1_2,-SQRT_1_2),ImVec2(-SQRT_1_2,SQRT_1_2)};
TransformMarker(marker, 4, c, s);
DrawList.AddLine(marker[0], marker[2], col_outline, weight);
@@ -871,7 +898,7 @@ inline void RenderMarkerCross(ImDrawList& DrawList, const ImVec2& c, float s, bo
}
template <typename Transformer, typename Getter>
-inline void RenderMarkers(Getter getter, Transformer transformer, ImDrawList& DrawList, ImPlotMarker marker, float size, bool rend_mk_line, ImU32 col_mk_line, float weight, bool rend_mk_fill, ImU32 col_mk_fill) {
+IMPLOT_INLINE void RenderMarkers(Getter getter, Transformer transformer, ImDrawList& DrawList, ImPlotMarker marker, float size, bool rend_mk_line, ImU32 col_mk_line, float weight, bool rend_mk_fill, ImU32 col_mk_fill) {
static void (*marker_table[ImPlotMarker_COUNT])(ImDrawList&, const ImVec2&, float s, bool, ImU32, bool, ImU32, float) = {
RenderMarkerCircle,
RenderMarkerSquare,
@@ -885,9 +912,10 @@ inline void RenderMarkers(Getter getter, Transformer transformer, ImDrawList& Dr
RenderMarkerAsterisk
};
ImPlotContext& gp = *GImPlot;
+ const ImRect& rect = gp.CurrentPlot->PlotRect;
for (int i = 0; i < getter.Count; ++i) {
ImVec2 c = transformer(getter(i));
- if (gp.CurrentPlot->PlotRect.Contains(c))
+ if (c.x >= rect.Min.x && c.y >= rect.Min.y && c.x <= rect.Max.x && c.y <= rect.Max.y)
marker_table[marker](DrawList, c, size, rend_mk_line, col_mk_line, rend_mk_fill, col_mk_fill, weight);
}
}
@@ -897,7 +925,7 @@ inline void RenderMarkers(Getter getter, Transformer transformer, ImDrawList& Dr
//-----------------------------------------------------------------------------
template <typename Getter>
-inline void PlotLineEx(const char* label_id, const Getter& getter) {
+IMPLOT_INLINE void PlotLineEx(const char* label_id, const Getter& getter) {
if (BeginItem(label_id, ImPlotCol_Line)) {
if (FitThisFrame()) {
for (int i = 0; i < getter.Count; ++i) {
@@ -918,8 +946,9 @@ inline void PlotLineEx(const char* label_id, const Getter& getter) {
}
// render markers
if (s.Marker != ImPlotMarker_None) {
- PopPlotClipRect();
- PushPlotClipRect(s.MarkerSize);
+ // uncomment lines below to render markers over plot rect border
+ // PopPlotClipRect();
+ // PushPlotClipRect(s.MarkerSize);
const ImU32 col_line = ImGui::GetColorU32(s.Colors[ImPlotCol_MarkerOutline]);
const ImU32 col_fill = ImGui::GetColorU32(s.Colors[ImPlotCol_MarkerFill]);
switch (GetCurrentScale()) {
@@ -933,9 +962,10 @@ inline void PlotLineEx(const char* label_id, const Getter& getter) {
}
}
+
template <typename T>
void PlotLine(const char* label_id, const T* values, int count, double xscale, double x0, int offset, int stride) {
- GetterYs<T> getter(values,count,xscale,x0,offset,stride);
+ GetterXY<GetterLin,GetterIdx<T>> getter(GetterLin(xscale,x0),GetterIdx<T>(values,count,offset,stride),count);
PlotLineEx(label_id, getter);
}
@@ -952,7 +982,7 @@ template IMPLOT_API void PlotLine<double>(const char* label_id, const double* va
template <typename T>
void PlotLine(const char* label_id, const T* xs, const T* ys, int count, int offset, int stride) {
- GetterXsYs<T> getter(xs,ys,count,offset,stride);
+ GetterXY<GetterIdx<T>,GetterIdx<T>> getter(GetterIdx<T>(xs,count,offset,stride),GetterIdx<T>(ys,count,offset,stride),count);
return PlotLineEx(label_id, getter);
}
@@ -968,8 +998,8 @@ template IMPLOT_API void PlotLine<float>(const char* label_id, const float* xs,
template IMPLOT_API void PlotLine<double>(const char* label_id, const double* xs, const double* ys, int count, int offset, int stride);
// custom
-void PlotLineG(const char* label_id, ImPlotPoint (*getter_func)(void* data, int idx), void* data, int count, int offset) {
- GetterFuncPtr getter(getter_func,data, count, offset);
+void PlotLineG(const char* label_id, ImPlotGetter getter_func, void* data, int count) {
+ GetterFuncPtr getter(getter_func,data, count);
return PlotLineEx(label_id, getter);
}
@@ -978,7 +1008,7 @@ void PlotLineG(const char* label_id, ImPlotPoint (*getter_func)(void* data, int
//-----------------------------------------------------------------------------
template <typename Getter>
-inline void PlotScatterEx(const char* label_id, const Getter& getter) {
+IMPLOT_INLINE void PlotScatterEx(const char* label_id, const Getter& getter) {
if (BeginItem(label_id, ImPlotCol_MarkerOutline)) {
if (FitThisFrame()) {
for (int i = 0; i < getter.Count; ++i) {
@@ -991,8 +1021,9 @@ inline void PlotScatterEx(const char* label_id, const Getter& getter) {
// render markers
ImPlotMarker marker = s.Marker == ImPlotMarker_None ? ImPlotMarker_Circle : s.Marker;
if (marker != ImPlotMarker_None) {
- PopPlotClipRect();
- PushPlotClipRect(s.MarkerSize);
+ // uncomment lines below to render markers over plot rect border
+ // PopPlotClipRect();
+ // PushPlotClipRect(s.MarkerSize);
const ImU32 col_line = ImGui::GetColorU32(s.Colors[ImPlotCol_MarkerOutline]);
const ImU32 col_fill = ImGui::GetColorU32(s.Colors[ImPlotCol_MarkerFill]);
switch (GetCurrentScale()) {
@@ -1008,7 +1039,7 @@ inline void PlotScatterEx(const char* label_id, const Getter& getter) {
template <typename T>
void PlotScatter(const char* label_id, const T* values, int count, double xscale, double x0, int offset, int stride) {
- GetterYs<T> getter(values,count,xscale,x0,offset,stride);
+ GetterXY<GetterLin,GetterIdx<T>> getter(GetterLin(xscale,x0),GetterIdx<T>(values,count,offset,stride),count);
PlotScatterEx(label_id, getter);
}
@@ -1025,7 +1056,7 @@ template IMPLOT_API void PlotScatter<double>(const char* label_id, const double*
template <typename T>
void PlotScatter(const char* label_id, const T* xs, const T* ys, int count, int offset, int stride) {
- GetterXsYs<T> getter(xs,ys,count,offset,stride);
+ GetterXY<GetterIdx<T>,GetterIdx<T>> getter(GetterIdx<T>(xs,count,offset,stride),GetterIdx<T>(ys,count,offset,stride),count);
return PlotScatterEx(label_id, getter);
}
@@ -1041,8 +1072,8 @@ template IMPLOT_API void PlotScatter<float>(const char* label_id, const float* x
template IMPLOT_API void PlotScatter<double>(const char* label_id, const double* xs, const double* ys, int count, int offset, int stride);
// custom
-void PlotScatterG(const char* label_id, ImPlotPoint (*getter_func)(void* data, int idx), void* data, int count, int offset) {
- GetterFuncPtr getter(getter_func,data, count, offset);
+void PlotScatterG(const char* label_id, ImPlotGetter getter_func, void* data, int count) {
+ GetterFuncPtr getter(getter_func,data, count);
return PlotScatterEx(label_id, getter);
}
@@ -1051,7 +1082,7 @@ void PlotScatterG(const char* label_id, ImPlotPoint (*getter_func)(void* data, i
//-----------------------------------------------------------------------------
template <typename Getter>
-inline void PlotStairsEx(const char* label_id, const Getter& getter) {
+IMPLOT_INLINE void PlotStairsEx(const char* label_id, const Getter& getter) {
if (BeginItem(label_id, ImPlotCol_Line)) {
if (FitThisFrame()) {
for (int i = 0; i < getter.Count; ++i) {
@@ -1089,7 +1120,7 @@ inline void PlotStairsEx(const char* label_id, const Getter& getter) {
template <typename T>
void PlotStairs(const char* label_id, const T* values, int count, double xscale, double x0, int offset, int stride) {
- GetterYs<T> getter(values,count,xscale,x0,offset,stride);
+ GetterXY<GetterLin,GetterIdx<T>> getter(GetterLin(xscale,x0),GetterIdx<T>(values,count,offset,stride),count);
PlotStairsEx(label_id, getter);
}
@@ -1106,7 +1137,7 @@ template IMPLOT_API void PlotStairs<double>(const char* label_id, const double*
template <typename T>
void PlotStairs(const char* label_id, const T* xs, const T* ys, int count, int offset, int stride) {
- GetterXsYs<T> getter(xs,ys,count,offset,stride);
+ GetterXY<GetterIdx<T>,GetterIdx<T>> getter(GetterIdx<T>(xs,count,offset,stride),GetterIdx<T>(ys,count,offset,stride),count);
return PlotStairsEx(label_id, getter);
}
@@ -1122,8 +1153,8 @@ template IMPLOT_API void PlotStairs<float>(const char* label_id, const float* xs
template IMPLOT_API void PlotStairs<double>(const char* label_id, const double* xs, const double* ys, int count, int offset, int stride);
// custom
-void PlotStairsG(const char* label_id, ImPlotPoint (*getter_func)(void* data, int idx), void* data, int count, int offset) {
- GetterFuncPtr getter(getter_func,data, count, offset);
+void PlotStairsG(const char* label_id, ImPlotGetter getter_func, void* data, int count) {
+ GetterFuncPtr getter(getter_func,data, count);
return PlotStairsEx(label_id, getter);
}
@@ -1132,7 +1163,7 @@ void PlotStairsG(const char* label_id, ImPlotPoint (*getter_func)(void* data, in
//-----------------------------------------------------------------------------
template <typename Getter1, typename Getter2>
-inline void PlotShadedEx(const char* label_id, const Getter1& getter1, const Getter2& getter2, bool fit2) {
+IMPLOT_INLINE void PlotShadedEx(const char* label_id, const Getter1& getter1, const Getter2& getter2, bool fit2) {
if (BeginItem(label_id, ImPlotCol_Fill)) {
if (FitThisFrame()) {
for (int i = 0; i < getter1.Count; ++i)
@@ -1160,16 +1191,16 @@ inline void PlotShadedEx(const char* label_id, const Getter1& getter1, const Get
template <typename T>
void PlotShaded(const char* label_id, const T* values, int count, double y_ref, double xscale, double x0, int offset, int stride) {
bool fit2 = true;
- if (y_ref == -HUGE_VAL) {
+ if (!(y_ref > -DBL_MAX)) { // filters out nans too
fit2 = false;
- y_ref = GetPlotLimits().Y.Min;
+ y_ref = GetPlotLimits(IMPLOT_AUTO,IMPLOT_AUTO).Y.Min;
}
- if (y_ref == HUGE_VAL) {
+ if (!(y_ref < DBL_MAX)) { // filters out nans too
fit2 = false;
- y_ref = GetPlotLimits().Y.Max;
+ y_ref = GetPlotLimits(IMPLOT_AUTO,IMPLOT_AUTO).Y.Max;
}
- GetterYs<T> getter1(values,count,xscale,x0,offset,stride);
- GetterYRef getter2(y_ref,count,xscale,x0);
+ GetterXY<GetterLin,GetterIdx<T>> getter1(GetterLin(xscale,x0),GetterIdx<T>(values,count,offset,stride),count);
+ GetterXY<GetterLin,GetterRef> getter2(GetterLin(xscale,x0),GetterRef(y_ref),count);
PlotShadedEx(label_id, getter1, getter2, fit2);
}
@@ -1187,16 +1218,16 @@ template IMPLOT_API void PlotShaded<double>(const char* label_id, const double*
template <typename T>
void PlotShaded(const char* label_id, const T* xs, const T* ys, int count, double y_ref, int offset, int stride) {
bool fit2 = true;
- if (y_ref == -HUGE_VAL) {
+ if (!(y_ref > -DBL_MAX)) { // filters out nans too
fit2 = false;
- y_ref = GetPlotLimits().Y.Min;
+ y_ref = GetPlotLimits(IMPLOT_AUTO,IMPLOT_AUTO).Y.Min;
}
- if (y_ref == HUGE_VAL) {
+ if (!(y_ref < DBL_MAX)) { // filters out nans too
fit2 = false;
- y_ref = GetPlotLimits().Y.Max;
+ y_ref = GetPlotLimits(IMPLOT_AUTO,IMPLOT_AUTO).Y.Max;
}
- GetterXsYs<T> getter1(xs, ys, count, offset, stride);
- GetterXsYRef<T> getter2(xs, y_ref, count, offset, stride);
+ GetterXY<GetterIdx<T>,GetterIdx<T>> getter1(GetterIdx<T>(xs,count,offset,stride),GetterIdx<T>(ys,count,offset,stride),count);
+ GetterXY<GetterIdx<T>,GetterRef> getter2(GetterIdx<T>(xs,count,offset,stride),GetterRef(y_ref),count);
PlotShadedEx(label_id, getter1, getter2, fit2);
}
@@ -1213,8 +1244,8 @@ template IMPLOT_API void PlotShaded<double>(const char* label_id, const double*
template <typename T>
void PlotShaded(const char* label_id, const T* xs, const T* ys1, const T* ys2, int count, int offset, int stride) {
- GetterXsYs<T> getter1(xs, ys1, count, offset, stride);
- GetterXsYs<T> getter2(xs, ys2, count, offset, stride);
+ GetterXY<GetterIdx<T>,GetterIdx<T>> getter1(GetterIdx<T>(xs,count,offset,stride),GetterIdx<T>(ys1,count,offset,stride),count);
+ GetterXY<GetterIdx<T>,GetterIdx<T>> getter2(GetterIdx<T>(xs,count,offset,stride),GetterIdx<T>(ys2,count,offset,stride),count);
PlotShadedEx(label_id, getter1, getter2, true);
}
@@ -1230,9 +1261,9 @@ template IMPLOT_API void PlotShaded<float>(const char* label_id, const float* xs
template IMPLOT_API void PlotShaded<double>(const char* label_id, const double* xs, const double* ys1, const double* ys2, int count, int offset, int stride);
// custom
-void PlotShadedG(const char* label_id, ImPlotPoint (*g1)(void* data, int idx), void* data1, ImPlotPoint (*g2)(void* data, int idx), void* data2, int count, int offset) {
- GetterFuncPtr getter1(g1, data1, count, offset);
- GetterFuncPtr getter2(g2, data2, count, offset);
+void PlotShadedG(const char* label_id, ImPlotGetter getter_func1, void* data1, ImPlotGetter getter_func2, void* data2, int count) {
+ GetterFuncPtr getter1(getter_func1, data1, count);
+ GetterFuncPtr getter2(getter_func2, data2, count);
PlotShadedEx(label_id, getter1, getter2, true);
}
@@ -1242,15 +1273,16 @@ void PlotShadedG(const char* label_id, ImPlotPoint (*g1)(void* data, int idx), v
// TODO: Migrate to RenderPrimitives
-template <typename Getter>
-void PlotBarsEx(const char* label_id, const Getter& getter, double width) {
+template <typename Getter1, typename Getter2>
+void PlotBarsEx(const char* label_id, const Getter1& getter1, const Getter2 getter2, double width) {
if (BeginItem(label_id, ImPlotCol_Fill)) {
const double half_width = width / 2;
if (FitThisFrame()) {
- for (int i = 0; i < getter.Count; ++i) {
- ImPlotPoint p = getter(i);
- FitPoint(ImPlotPoint(p.x - half_width, p.y));
- FitPoint(ImPlotPoint(p.x + half_width, 0));
+ for (int i = 0; i < getter1.Count; ++i) {
+ ImPlotPoint p1 = getter1(i);
+ ImPlotPoint p2 = getter2(i);
+ FitPoint(ImPlotPoint(p1.x - half_width, p1.y));
+ FitPoint(ImPlotPoint(p2.x + half_width, p2.y));
}
}
const ImPlotNextItemData& s = GetItemData();
@@ -1260,12 +1292,20 @@ void PlotBarsEx(const char* label_id, const Getter& getter, double width) {
bool rend_line = s.RenderLine;
if (s.RenderFill && col_line == col_fill)
rend_line = false;
- for (int i = 0; i < getter.Count; ++i) {
- ImPlotPoint p = getter(i);
- if (p.y == 0)
+ for (int i = 0; i < getter1.Count; ++i) {
+ ImPlotPoint p1 = getter1(i);
+ ImPlotPoint p2 = getter2(i);
+ if (p1.y == p2.y)
continue;
- ImVec2 a = PlotToPixels(p.x - half_width, p.y);
- ImVec2 b = PlotToPixels(p.x + half_width, 0);
+ ImVec2 a = PlotToPixels(p1.x - half_width, p1.y,IMPLOT_AUTO,IMPLOT_AUTO);
+ ImVec2 b = PlotToPixels(p2.x + half_width, p2.y,IMPLOT_AUTO,IMPLOT_AUTO);
+ float width_px = ImAbs(a.x-b.x);
+ if (width_px < 1.0f) {
+ a.x += a.x > b.x ? (1-width_px) / 2 : (width_px-1) / 2;
+ b.x += b.x > a.x ? (1-width_px) / 2 : (width_px-1) / 2;
+ }
+ // a.x = IM_ROUND(a.x);
+ // b.x = IM_ROUND(b.x);
if (s.RenderFill)
DrawList.AddRectFilled(a, b, col_fill);
if (rend_line)
@@ -1277,8 +1317,9 @@ void PlotBarsEx(const char* label_id, const Getter& getter, double width) {
template <typename T>
void PlotBars(const char* label_id, const T* values, int count, double width, double shift, int offset, int stride) {
- GetterBarV<T> getter(values,shift,count,offset,stride);
- PlotBarsEx(label_id, getter, width);
+ GetterXY<GetterLin,GetterIdx<T>> getter1(GetterLin(1.0,shift),GetterIdx<T>(values,count,offset,stride),count);
+ GetterXY<GetterLin,GetterRef> getter2(GetterLin(1.0,shift),GetterRef(0),count);
+ PlotBarsEx(label_id, getter1, getter2, width);
}
template IMPLOT_API void PlotBars<ImS8>(const char* label_id, const ImS8* values, int count, double width, double shift, int offset, int stride);
@@ -1294,8 +1335,9 @@ template IMPLOT_API void PlotBars<double>(const char* label_id, const double* va
template <typename T>
void PlotBars(const char* label_id, const T* xs, const T* ys, int count, double width, int offset, int stride) {
- GetterXsYs<T> getter(xs,ys,count,offset,stride);
- PlotBarsEx(label_id, getter, width);
+ GetterXY<GetterIdx<T>,GetterIdx<T>> getter1(GetterIdx<T>(xs,count,offset,stride),GetterIdx<T>(ys,count,offset,stride),count);
+ GetterXY<GetterIdx<T>,GetterRef> getter2(GetterIdx<T>(xs,count,offset,stride),GetterRef(0),count);
+ PlotBarsEx(label_id, getter1, getter2, width);
}
template IMPLOT_API void PlotBars<ImS8>(const char* label_id, const ImS8* xs, const ImS8* ys, int count, double width, int offset, int stride);
@@ -1310,9 +1352,10 @@ template IMPLOT_API void PlotBars<float>(const char* label_id, const float* xs,
template IMPLOT_API void PlotBars<double>(const char* label_id, const double* xs, const double* ys, int count, double width, int offset, int stride);
// custom
-void PlotBarsG(const char* label_id, ImPlotPoint (*getter_func)(void* data, int idx), void* data, int count, double width, int offset) {
- GetterFuncPtr getter(getter_func, data, count, offset);
- PlotBarsEx(label_id, getter, width);
+void PlotBarsG(const char* label_id, ImPlotGetter getter_func, void* data, int count, double width) {
+ GetterFuncPtr getter1(getter_func, data, count);
+ GetterOverrideY<GetterFuncPtr> getter2(getter1,0);
+ PlotBarsEx(label_id, getter1, getter2, width);
}
//-----------------------------------------------------------------------------
@@ -1321,15 +1364,16 @@ void PlotBarsG(const char* label_id, ImPlotPoint (*getter_func)(void* data, int
// TODO: Migrate to RenderPrimitives
-template <typename Getter, typename THeight>
-void PlotBarsHEx(const char* label_id, const Getter& getter, THeight height) {
+template <typename Getter1, typename Getter2>
+void PlotBarsHEx(const char* label_id, const Getter1& getter1, const Getter2& getter2, double height) {
if (BeginItem(label_id, ImPlotCol_Fill)) {
- const THeight half_height = height / 2;
+ const double half_height = height / 2;
if (FitThisFrame()) {
- for (int i = 0; i < getter.Count; ++i) {
- ImPlotPoint p = getter(i);
- FitPoint(ImPlotPoint(0, p.y - half_height));
- FitPoint(ImPlotPoint(p.x, p.y + half_height));
+ for (int i = 0; i < getter1.Count; ++i) {
+ ImPlotPoint p1 = getter1(i);
+ ImPlotPoint p2 = getter2(i);
+ FitPoint(ImPlotPoint(p1.x, p1.y - half_height));
+ FitPoint(ImPlotPoint(p2.x, p2.y + half_height));
}
}
const ImPlotNextItemData& s = GetItemData();
@@ -1339,12 +1383,13 @@ void PlotBarsHEx(const char* label_id, const Getter& getter, THeight height) {
bool rend_line = s.RenderLine;
if (s.RenderFill && col_line == col_fill)
rend_line = false;
- for (int i = 0; i < getter.Count; ++i) {
- ImPlotPoint p = getter(i);
- if (p.x == 0)
+ for (int i = 0; i < getter1.Count; ++i) {
+ ImPlotPoint p1 = getter1(i);
+ ImPlotPoint p2 = getter2(i);
+ if (p1.x == p2.x)
continue;
- ImVec2 a = PlotToPixels(0, p.y - half_height);
- ImVec2 b = PlotToPixels(p.x, p.y + half_height);
+ ImVec2 a = PlotToPixels(p1.x, p1.y - half_height,IMPLOT_AUTO,IMPLOT_AUTO);
+ ImVec2 b = PlotToPixels(p2.x, p2.y + half_height,IMPLOT_AUTO,IMPLOT_AUTO);
if (s.RenderFill)
DrawList.AddRectFilled(a, b, col_fill);
if (rend_line)
@@ -1356,8 +1401,9 @@ void PlotBarsHEx(const char* label_id, const Getter& getter, THeight height) {
template <typename T>
void PlotBarsH(const char* label_id, const T* values, int count, double height, double shift, int offset, int stride) {
- GetterBarH<T> getter(values,shift,count,offset,stride);
- PlotBarsHEx(label_id, getter, height);
+ GetterXY<GetterIdx<T>,GetterLin> getter1(GetterIdx<T>(values,count,offset,stride),GetterLin(1.0,shift),count);
+ GetterXY<GetterRef,GetterLin> getter2(GetterRef(0),GetterLin(1.0,shift),count);
+ PlotBarsHEx(label_id, getter1, getter2, height);
}
template IMPLOT_API void PlotBarsH<ImS8>(const char* label_id, const ImS8* values, int count, double height, double shift, int offset, int stride);
@@ -1373,8 +1419,9 @@ template IMPLOT_API void PlotBarsH<double>(const char* label_id, const double* v
template <typename T>
void PlotBarsH(const char* label_id, const T* xs, const T* ys, int count, double height, int offset, int stride) {
- GetterXsYs<T> getter(xs,ys,count,offset,stride);
- PlotBarsHEx(label_id, getter, height);
+ GetterXY<GetterIdx<T>,GetterIdx<T>> getter1(GetterIdx<T>(xs,count,offset,stride),GetterIdx<T>(ys,count,offset,stride),count);
+ GetterXY<GetterRef, GetterIdx<T>> getter2(GetterRef(0),GetterIdx<T>(ys,count,offset,stride),count);
+ PlotBarsHEx(label_id, getter1, getter2, height);
}
template IMPLOT_API void PlotBarsH<ImS8>(const char* label_id, const ImS8* xs, const ImS8* ys, int count, double height, int offset, int stride);
@@ -1389,11 +1436,122 @@ template IMPLOT_API void PlotBarsH<float>(const char* label_id, const float* xs,
template IMPLOT_API void PlotBarsH<double>(const char* label_id, const double* xs, const double* ys, int count, double height, int offset, int stride);
// custom
-void PlotBarsHG(const char* label_id, ImPlotPoint (*getter_func)(void* data, int idx), void* data, int count, double height, int offset) {
- GetterFuncPtr getter(getter_func, data, count, offset);
- PlotBarsHEx(label_id, getter, height);
+void PlotBarsHG(const char* label_id, ImPlotGetter getter_func, void* data, int count, double height) {
+ GetterFuncPtr getter1(getter_func, data, count);
+ GetterOverrideX<GetterFuncPtr> getter2(getter1,0);
+ PlotBarsHEx(label_id, getter1, getter2, height);
+}
+
+//-----------------------------------------------------------------------------
+// PLOT BAR GROUPS
+//-----------------------------------------------------------------------------
+
+template <typename T>
+void PlotBarGroups(const char* const label_ids[], const T* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags) {
+ if (ImHasFlag(flags, ImPlotBarGroupsFlags_Stacked)) {
+ SetupLock();
+ GImPlot->TempDouble1.resize(4*groups);
+ double* temp = GImPlot->TempDouble1.Data;
+ double* neg = &temp[0];
+ double* pos = &temp[groups];
+ double* curr_min = &temp[groups*2];
+ double* curr_max = &temp[groups*3];
+ for (int g = 0; g < groups*2; ++g)
+ temp[g] = 0;
+ for (int i = 0; i < items; ++i) {
+ if (!IsItemHidden(label_ids[i])) {
+ for (int g = 0; g < groups; ++g) {
+ double v = (double)values[i*groups+g];
+ if (v > 0) {
+ curr_min[g] = pos[g];
+ curr_max[g] = curr_min[g] + v;
+ pos[g] += v;
+ }
+ else {
+ curr_max[g] = neg[g];
+ curr_min[g] = curr_max[g] + v;
+ neg[g] += v;
+ }
+ }
+ }
+ GetterXY<GetterLin,GetterIdx<double>> getter1(GetterLin(1.0,shift),GetterIdx<double>(curr_min,groups),groups);
+ GetterXY<GetterLin,GetterIdx<double>> getter2(GetterLin(1.0,shift),GetterIdx<double>(curr_max,groups),groups);
+ PlotBarsEx(label_ids[i],getter1,getter2,width);
+ }
+ }
+ else {
+ const double subwidth = width / items;
+ for (int i = 0; i < items; ++i) {
+ const double subshift = (i+0.5)*subwidth - width/2;
+ PlotBars(label_ids[i],&values[i*groups],groups,subwidth,subshift+shift);
+ }
+ }
+}
+
+template IMPLOT_API void PlotBarGroups<ImS8>(const char* const label_ids[], const ImS8* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags);
+template IMPLOT_API void PlotBarGroups<ImU8>(const char* const label_ids[], const ImU8* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags);
+template IMPLOT_API void PlotBarGroups<ImS16>(const char* const label_ids[], const ImS16* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags);
+template IMPLOT_API void PlotBarGroups<ImU16>(const char* const label_ids[], const ImU16* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags);
+template IMPLOT_API void PlotBarGroups<ImS32>(const char* const label_ids[], const ImS32* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags);
+template IMPLOT_API void PlotBarGroups<ImU32>(const char* const label_ids[], const ImU32* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags);
+template IMPLOT_API void PlotBarGroups<ImS64>(const char* const label_ids[], const ImS64* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags);
+template IMPLOT_API void PlotBarGroups<ImU64>(const char* const label_ids[], const ImU64* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags);
+template IMPLOT_API void PlotBarGroups<float>(const char* const label_ids[], const float* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags);
+template IMPLOT_API void PlotBarGroups<double>(const char* const label_ids[], const double* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags);
+
+template <typename T>
+void PlotBarGroupsH(const char* const label_ids[], const T* values, int items, int groups, double height, double shift, ImPlotBarGroupsFlags flags) {
+ if (ImHasFlag(flags, ImPlotBarGroupsFlags_Stacked)) {
+ SetupLock();
+ GImPlot->TempDouble1.resize(4*groups);
+ double* temp = GImPlot->TempDouble1.Data;
+ double* neg = &temp[0];
+ double* pos = &temp[groups];
+ double* curr_min = &temp[groups*2];
+ double* curr_max = &temp[groups*3];
+ for (int g = 0; g < groups*2; ++g)
+ temp[g] = 0;
+ for (int i = 0; i < items; ++i) {
+ if (!IsItemHidden(label_ids[i])) {
+ for (int g = 0; g < groups; ++g) {
+ double v = (double)values[i*groups+g];
+ if (v > 0) {
+ curr_min[g] = pos[g];
+ curr_max[g] = curr_min[g] + v;
+ pos[g] += v;
+ }
+ else {
+ curr_max[g] = neg[g];
+ curr_min[g] = curr_max[g] + v;
+ neg[g] += v;
+ }
+ }
+ }
+ GetterXY<GetterIdx<double>,GetterLin> getter1(GetterIdx<double>(curr_min,groups),GetterLin(1.0,shift),groups);
+ GetterXY<GetterIdx<double>,GetterLin> getter2(GetterIdx<double>(curr_max,groups),GetterLin(1.0,shift),groups);
+ PlotBarsHEx(label_ids[i],getter1,getter2,height);
+ }
+ }
+ else {
+ const double subheight = height / items;
+ for (int i = 0; i < items; ++i) {
+ const double subshift = (i+0.5)*subheight - height/2;
+ PlotBarsH(label_ids[i],&values[i*groups],groups,subheight,subshift+shift);
+ }
+ }
}
+template IMPLOT_API void PlotBarGroupsH<ImS8>(const char* const label_ids[], const ImS8* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags);
+template IMPLOT_API void PlotBarGroupsH<ImU8>(const char* const label_ids[], const ImU8* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags);
+template IMPLOT_API void PlotBarGroupsH<ImS16>(const char* const label_ids[], const ImS16* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags);
+template IMPLOT_API void PlotBarGroupsH<ImU16>(const char* const label_ids[], const ImU16* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags);
+template IMPLOT_API void PlotBarGroupsH<ImS32>(const char* const label_ids[], const ImS32* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags);
+template IMPLOT_API void PlotBarGroupsH<ImU32>(const char* const label_ids[], const ImU32* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags);
+template IMPLOT_API void PlotBarGroupsH<ImS64>(const char* const label_ids[], const ImS64* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags);
+template IMPLOT_API void PlotBarGroupsH<ImU64>(const char* const label_ids[], const ImU64* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags);
+template IMPLOT_API void PlotBarGroupsH<float>(const char* const label_ids[], const float* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags);
+template IMPLOT_API void PlotBarGroupsH<double>(const char* const label_ids[], const double* values, int items, int groups, double width, double shift, ImPlotBarGroupsFlags flags);
+
//-----------------------------------------------------------------------------
// PLOT ERROR BARS
//-----------------------------------------------------------------------------
@@ -1415,8 +1573,8 @@ void PlotErrorBarsEx(const char* label_id, const Getter& getter) {
const float half_whisker = s.ErrorBarSize * 0.5f;
for (int i = 0; i < getter.Count; ++i) {
ImPlotPointError e = getter(i);
- ImVec2 p1 = PlotToPixels(e.X, e.Y - e.Neg);
- ImVec2 p2 = PlotToPixels(e.X, e.Y + e.Pos);
+ ImVec2 p1 = PlotToPixels(e.X, e.Y - e.Neg,IMPLOT_AUTO,IMPLOT_AUTO);
+ ImVec2 p2 = PlotToPixels(e.X, e.Y + e.Pos,IMPLOT_AUTO,IMPLOT_AUTO);
DrawList.AddLine(p1,p2,col, s.ErrorBarWeight);
if (rend_whisker) {
DrawList.AddLine(p1 - ImVec2(half_whisker, 0), p1 + ImVec2(half_whisker, 0), col, s.ErrorBarWeight);
@@ -1482,8 +1640,8 @@ void PlotErrorBarsHEx(const char* label_id, const Getter& getter) {
const float half_whisker = s.ErrorBarSize * 0.5f;
for (int i = 0; i < getter.Count; ++i) {
ImPlotPointError e = getter(i);
- ImVec2 p1 = PlotToPixels(e.X - e.Neg, e.Y);
- ImVec2 p2 = PlotToPixels(e.X + e.Pos, e.Y);
+ ImVec2 p1 = PlotToPixels(e.X - e.Neg, e.Y,IMPLOT_AUTO,IMPLOT_AUTO);
+ ImVec2 p2 = PlotToPixels(e.X + e.Pos, e.Y,IMPLOT_AUTO,IMPLOT_AUTO);
DrawList.AddLine(p1, p2, col, s.ErrorBarWeight);
if (rend_whisker) {
DrawList.AddLine(p1 - ImVec2(0, half_whisker), p1 + ImVec2(0, half_whisker), col, s.ErrorBarWeight);
@@ -1533,7 +1691,7 @@ template IMPLOT_API void PlotErrorBarsH<double>(const char* label_id, const doub
//-----------------------------------------------------------------------------
template <typename GetterM, typename GetterB>
-inline void PlotStemsEx(const char* label_id, const GetterM& get_mark, const GetterB& get_base) {
+IMPLOT_INLINE void PlotStemsEx(const char* label_id, const GetterM& get_mark, const GetterB& get_base) {
if (BeginItem(label_id, ImPlotCol_Line)) {
if (FitThisFrame()) {
for (int i = 0; i < get_base.Count; ++i) {
@@ -1573,8 +1731,8 @@ inline void PlotStemsEx(const char* label_id, const GetterM& get_mark, const Get
template <typename T>
void PlotStems(const char* label_id, const T* values, int count, double y_ref, double xscale, double x0, int offset, int stride) {
- GetterYs<T> get_mark(values,count,xscale,x0,offset,stride);
- GetterYRef get_base(y_ref,count,xscale,x0);
+ GetterXY<GetterLin,GetterIdx<T>> get_mark(GetterLin(xscale,x0),GetterIdx<T>(values,count,offset,stride),count);
+ GetterXY<GetterLin,GetterRef> get_base(GetterLin(xscale,x0),GetterRef(y_ref),count);
PlotStemsEx(label_id, get_mark, get_base);
}
@@ -1591,8 +1749,8 @@ template IMPLOT_API void PlotStems<double>(const char* label_id, const double* v
template <typename T>
void PlotStems(const char* label_id, const T* xs, const T* ys, int count, double y_ref, int offset, int stride) {
- GetterXsYs<T> get_mark(xs,ys,count,offset,stride);
- GetterXsYRef<T> get_base(xs,y_ref,count,offset,stride);
+ GetterXY<GetterIdx<T>,GetterIdx<T>> get_mark(GetterIdx<T>(xs,count,offset,stride),GetterIdx<T>(ys,count,offset,stride),count);
+ GetterXY<GetterIdx<T>,GetterRef> get_base(GetterIdx<T>(xs,count,offset,stride),GetterRef(y_ref),count);
PlotStemsEx(label_id, get_mark, get_base);
}
@@ -1614,9 +1772,9 @@ template IMPLOT_API void PlotStems<double>(const char* label_id, const double* x
template <typename T>
void PlotVLines(const char* label_id, const T* xs, int count, int offset, int stride) {
if (BeginItem(label_id, ImPlotCol_Line)) {
- const ImPlotLimits lims = GetPlotLimits();
- GetterXsYRef<T> get_min(xs,lims.Y.Min,count,offset,stride);
- GetterXsYRef<T> get_max(xs,lims.Y.Max,count,offset,stride);
+ const ImPlotRect lims = GetPlotLimits(IMPLOT_AUTO,IMPLOT_AUTO);
+ GetterXY<GetterIdx<T>,GetterRef> get_min(GetterIdx<T>(xs,count,offset,stride),GetterRef(lims.Y.Min),count);
+ GetterXY<GetterIdx<T>,GetterRef> get_max(GetterIdx<T>(xs,count,offset,stride),GetterRef(lims.Y.Max),count);
if (FitThisFrame()) {
for (int i = 0; i < get_min.Count; ++i)
FitPointX(get_min(i).x);
@@ -1652,9 +1810,9 @@ template IMPLOT_API void PlotVLines<double>(const char* label_id, const double*
template <typename T>
void PlotHLines(const char* label_id, const T* ys, int count, int offset, int stride) {
if (BeginItem(label_id, ImPlotCol_Line)) {
- const ImPlotLimits lims = GetPlotLimits();
- GetterXRefYs<T> get_min(lims.X.Min,ys,count,offset,stride);
- GetterXRefYs<T> get_max(lims.X.Max,ys,count,offset,stride);
+ const ImPlotRect lims = GetPlotLimits(IMPLOT_AUTO,IMPLOT_AUTO);
+ GetterXY<GetterRef,GetterIdx<T>> get_min(GetterRef(lims.X.Min),GetterIdx<T>(ys,count,offset,stride),count);
+ GetterXY<GetterRef,GetterIdx<T>> get_max(GetterRef(lims.X.Max),GetterIdx<T>(ys,count,offset,stride),count);
if (FitThisFrame()) {
for (int i = 0; i < get_min.Count; ++i)
FitPointY(get_min(i).y);
@@ -1690,15 +1848,15 @@ template IMPLOT_API void PlotHLines<double>(const char* label_id, const double*
// PLOT PIE CHART
//-----------------------------------------------------------------------------
-inline void RenderPieSlice(ImDrawList& DrawList, const ImPlotPoint& center, double radius, double a0, double a1, ImU32 col) {
+IMPLOT_INLINE void RenderPieSlice(ImDrawList& DrawList, const ImPlotPoint& center, double radius, double a0, double a1, ImU32 col) {
static const float resolution = 50 / (2 * IM_PI);
static ImVec2 buffer[50];
- buffer[0] = PlotToPixels(center);
+ buffer[0] = PlotToPixels(center,IMPLOT_AUTO,IMPLOT_AUTO);
int n = ImMax(3, (int)((a1 - a0) * resolution));
double da = (a1 - a0) / (n - 1);
for (int i = 0; i < n; ++i) {
double a = a0 + i * da;
- buffer[i + 1] = PlotToPixels(center.x + radius * cos(a), center.y + radius * sin(a));
+ buffer[i + 1] = PlotToPixels(center.x + radius * cos(a), center.y + radius * sin(a),IMPLOT_AUTO,IMPLOT_AUTO);
}
DrawList.AddConvexPolyFilled(buffer, n + 1, col);
}
@@ -1719,6 +1877,10 @@ void PlotPieChart(const char* const label_ids[], const T* values, int count, dou
double percent = normalize ? (double)values[i] / sum : (double)values[i];
a1 = a0 + 2 * IM_PI * percent;
if (BeginItem(label_ids[i])) {
+ if (FitThisFrame()) {
+ FitPoint(ImPlotPoint(x-radius,y-radius));
+ FitPoint(ImPlotPoint(x+radius,y+radius));
+ }
ImU32 col = GetCurrentItem()->Color;
if (percent < 0.5) {
RenderPieSlice(DrawList, center, radius, a0, a1, col);
@@ -1740,10 +1902,10 @@ void PlotPieChart(const char* const label_ids[], const T* values, int count, dou
double percent = normalize ? (double)values[i] / sum : (double)values[i];
a1 = a0 + 2 * IM_PI * percent;
if (item->Show) {
- sprintf(buffer, fmt, (double)values[i]);
+ ImFormatString(buffer, 32, fmt, (double)values[i]);
ImVec2 size = ImGui::CalcTextSize(buffer);
double angle = a0 + (a1 - a0) * 0.5;
- ImVec2 pos = PlotToPixels(center.x + 0.5 * radius * cos(angle), center.y + 0.5 * radius * sin(angle));
+ ImVec2 pos = PlotToPixels(center.x + 0.5 * radius * cos(angle), center.y + 0.5 * radius * sin(angle),IMPLOT_AUTO,IMPLOT_AUTO);
ImU32 col = CalcTextColor(ImGui::ColorConvertU32ToFloat4(item->Color));
DrawList.AddText(pos - size * 0.5f, col, buffer);
}
@@ -1775,12 +1937,12 @@ struct RectInfo {
template <typename TGetter, typename TTransformer>
struct RectRenderer {
- inline RectRenderer(const TGetter& getter, const TTransformer& transformer) :
+ IMPLOT_INLINE RectRenderer(const TGetter& getter, const TTransformer& transformer) :
Getter(getter),
Transformer(transformer),
Prims(Getter.Count)
{}
- inline bool operator()(ImDrawList& DrawList, const ImRect& cull_rect, const ImVec2& uv, int prim) const {
+ IMPLOT_INLINE bool operator()(ImDrawList& DrawList, const ImRect& cull_rect, const ImVec2& uv, int prim) const {
RectInfo rect = Getter(prim);
ImVec2 P1 = Transformer(rect.Min);
ImVec2 P2 = Transformer(rect.Max);
@@ -1837,7 +1999,7 @@ struct GetterHeatmap {
HalfSize(Width*0.5, Height*0.5)
{ }
- inline RectInfo operator()(int idx) const {
+ template <typename I> IMPLOT_INLINE RectInfo operator()(I idx) const {
double val = (double)Values[idx];
const int r = idx / Cols;
const int c = idx % Cols;
@@ -1894,7 +2056,7 @@ void RenderHeatmap(Transformer transformer, ImDrawList& DrawList, const T* value
p.y = yref + ydir * (0.5*h + r*h);
ImVec2 px = transformer(p);
char buff[32];
- sprintf(buff, fmt, values[i]);
+ ImFormatString(buff, 32, fmt, values[i]);
ImVec2 size = ImGui::CalcTextSize(buff);
double t = ImClamp(ImRemap01((double)values[i], scale_min, scale_max),0.0,1.0);
ImVec4 color = SampleColormap((float)t);
@@ -1958,8 +2120,8 @@ double PlotHistogram(const char* label_id, const T* values, int count, int bins,
else
width = range.Size() / bins;
- ImVector<double>& bin_centers = GImPlot->Temp1;
- ImVector<double>& bin_counts = GImPlot->Temp2;
+ ImVector<double>& bin_centers = GImPlot->TempDouble1;
+ ImVector<double>& bin_counts = GImPlot->TempDouble2;
bin_centers.resize(bins);
bin_counts.resize(bins);
int below = 0;
@@ -2026,7 +2188,7 @@ template IMPLOT_API double PlotHistogram<double>(const char* label_id, const dou
//-----------------------------------------------------------------------------
template <typename T>
-double PlotHistogram2D(const char* label_id, const T* xs, const T* ys, int count, int x_bins, int y_bins, bool density, ImPlotLimits range, bool outliers) {
+double PlotHistogram2D(const char* label_id, const T* xs, const T* ys, int count, int x_bins, int y_bins, bool density, ImPlotRect range, bool outliers) {
if (count <= 0 || x_bins == 0 || y_bins == 0)
return 0;
@@ -2056,7 +2218,7 @@ double PlotHistogram2D(const char* label_id, const T* xs, const T* ys, int count
const int bins = x_bins * y_bins;
- ImVector<double>& bin_counts = GImPlot->Temp1;
+ ImVector<double>& bin_counts = GImPlot->TempDouble1;
bin_counts.resize(bins);
for (int b = 0; b < bins; ++b)
@@ -2099,16 +2261,16 @@ double PlotHistogram2D(const char* label_id, const T* xs, const T* ys, int count
return max_count;
}
-template IMPLOT_API double PlotHistogram2D<ImS8>(const char* label_id, const ImS8* xs, const ImS8* ys, int count, int x_bins, int y_bins, bool density, ImPlotLimits range, bool outliers);
-template IMPLOT_API double PlotHistogram2D<ImU8>(const char* label_id, const ImU8* xs, const ImU8* ys, int count, int x_bins, int y_bins, bool density, ImPlotLimits range, bool outliers);
-template IMPLOT_API double PlotHistogram2D<ImS16>(const char* label_id, const ImS16* xs, const ImS16* ys, int count, int x_bins, int y_bins, bool density, ImPlotLimits range, bool outliers);
-template IMPLOT_API double PlotHistogram2D<ImU16>(const char* label_id, const ImU16* xs, const ImU16* ys, int count, int x_bins, int y_bins, bool density, ImPlotLimits range, bool outliers);
-template IMPLOT_API double PlotHistogram2D<ImS32>(const char* label_id, const ImS32* xs, const ImS32* ys, int count, int x_bins, int y_bins, bool density, ImPlotLimits range, bool outliers);
-template IMPLOT_API double PlotHistogram2D<ImU32>(const char* label_id, const ImU32* xs, const ImU32* ys, int count, int x_bins, int y_bins, bool density, ImPlotLimits range, bool outliers);
-template IMPLOT_API double PlotHistogram2D<ImS64>(const char* label_id, const ImS64* xs, const ImS64* ys, int count, int x_bins, int y_bins, bool density, ImPlotLimits range, bool outliers);
-template IMPLOT_API double PlotHistogram2D<ImU64>(const char* label_id, const ImU64* xs, const ImU64* ys, int count, int x_bins, int y_bins, bool density, ImPlotLimits range, bool outliers);
-template IMPLOT_API double PlotHistogram2D<float>(const char* label_id, const float* xs, const float* ys, int count, int x_bins, int y_bins, bool density, ImPlotLimits range, bool outliers);
-template IMPLOT_API double PlotHistogram2D<double>(const char* label_id, const double* xs, const double* ys, int count, int x_bins, int y_bins, bool density, ImPlotLimits range, bool outliers);
+template IMPLOT_API double PlotHistogram2D<ImS8>(const char* label_id, const ImS8* xs, const ImS8* ys, int count, int x_bins, int y_bins, bool density, ImPlotRect range, bool outliers);
+template IMPLOT_API double PlotHistogram2D<ImU8>(const char* label_id, const ImU8* xs, const ImU8* ys, int count, int x_bins, int y_bins, bool density, ImPlotRect range, bool outliers);
+template IMPLOT_API double PlotHistogram2D<ImS16>(const char* label_id, const ImS16* xs, const ImS16* ys, int count, int x_bins, int y_bins, bool density, ImPlotRect range, bool outliers);
+template IMPLOT_API double PlotHistogram2D<ImU16>(const char* label_id, const ImU16* xs, const ImU16* ys, int count, int x_bins, int y_bins, bool density, ImPlotRect range, bool outliers);
+template IMPLOT_API double PlotHistogram2D<ImS32>(const char* label_id, const ImS32* xs, const ImS32* ys, int count, int x_bins, int y_bins, bool density, ImPlotRect range, bool outliers);
+template IMPLOT_API double PlotHistogram2D<ImU32>(const char* label_id, const ImU32* xs, const ImU32* ys, int count, int x_bins, int y_bins, bool density, ImPlotRect range, bool outliers);
+template IMPLOT_API double PlotHistogram2D<ImS64>(const char* label_id, const ImS64* xs, const ImS64* ys, int count, int x_bins, int y_bins, bool density, ImPlotRect range, bool outliers);
+template IMPLOT_API double PlotHistogram2D<ImU64>(const char* label_id, const ImU64* xs, const ImU64* ys, int count, int x_bins, int y_bins, bool density, ImPlotRect range, bool outliers);
+template IMPLOT_API double PlotHistogram2D<float>(const char* label_id, const float* xs, const float* ys, int count, int x_bins, int y_bins, bool density, ImPlotRect range, bool outliers);
+template IMPLOT_API double PlotHistogram2D<double>(const char* label_id, const double* xs, const double* ys, int count, int x_bins, int y_bins, bool density, ImPlotRect range, bool outliers);
//-----------------------------------------------------------------------------
// PLOT DIGITAL
@@ -2117,13 +2279,16 @@ template IMPLOT_API double PlotHistogram2D<double>(const char* label_id, const d
// TODO: Make this behave like all the other plot types (.e. not fixed in y axis)
template <typename Getter>
-inline void PlotDigitalEx(const char* label_id, Getter getter) {
+IMPLOT_INLINE void PlotDigitalEx(const char* label_id, Getter getter) {
if (BeginItem(label_id, ImPlotCol_Fill)) {
ImPlotContext& gp = *GImPlot;
ImDrawList& DrawList = *GetPlotDrawList();
const ImPlotNextItemData& s = GetItemData();
if (getter.Count > 1 && s.RenderFill) {
- const int y_axis = GetCurrentYAxis();
+ ImPlotPlot& plot = *gp.CurrentPlot;
+ ImPlotAxis& x_axis = plot.Axes[plot.CurrentX];
+ ImPlotAxis& y_axis = plot.Axes[plot.CurrentY];
+
int pixYMax = 0;
ImPlotPoint itemData1 = getter(0);
for (int i = 0; i < getter.Count; ++i) {
@@ -2139,24 +2304,24 @@ inline void PlotDigitalEx(const char* label_id, Getter getter) {
int pixY_1 = (int)(pixY_1_float); //allow only positive values
int pixY_chPosOffset = (int)(ImMax(s.DigitalBitHeight, pixY_1_float) + s.DigitalBitGap);
pixYMax = ImMax(pixYMax, pixY_chPosOffset);
- ImVec2 pMin = PlotToPixels(itemData1);
- ImVec2 pMax = PlotToPixels(itemData2);
- int pixY_Offset = 20; //20 pixel from bottom due to mouse cursor label
- pMin.y = (gp.PixelRange[y_axis].Min.y) + ((-gp.DigitalPlotOffset) - pixY_Offset);
- pMax.y = (gp.PixelRange[y_axis].Min.y) + ((-gp.DigitalPlotOffset) - pixY_0 - pixY_1 - pixY_Offset);
+ ImVec2 pMin = PlotToPixels(itemData1,IMPLOT_AUTO,IMPLOT_AUTO);
+ ImVec2 pMax = PlotToPixels(itemData2,IMPLOT_AUTO,IMPLOT_AUTO);
+ int pixY_Offset = 0; //20 pixel from bottom due to mouse cursor label
+ pMin.y = (y_axis.PixelMin) + ((-gp.DigitalPlotOffset) - pixY_Offset);
+ pMax.y = (y_axis.PixelMin) + ((-gp.DigitalPlotOffset) - pixY_0 - pixY_1 - pixY_Offset);
//plot only one rectangle for same digital state
while (((i+2) < getter.Count) && (itemData1.y == itemData2.y)) {
const int in = (i + 1);
itemData2 = getter(in);
if (ImNanOrInf(itemData2.y)) break;
- pMax.x = PlotToPixels(itemData2).x;
+ pMax.x = PlotToPixels(itemData2,IMPLOT_AUTO,IMPLOT_AUTO).x;
i++;
}
//do not extend plot outside plot range
- if (pMin.x < gp.PixelRange[y_axis].Min.x) pMin.x = gp.PixelRange[y_axis].Min.x;
- if (pMax.x < gp.PixelRange[y_axis].Min.x) pMax.x = gp.PixelRange[y_axis].Min.x;
- if (pMin.x > gp.PixelRange[y_axis].Max.x) pMin.x = gp.PixelRange[y_axis].Max.x;
- if (pMax.x > gp.PixelRange[y_axis].Max.x) pMax.x = gp.PixelRange[y_axis].Max.x;
+ if (pMin.x < x_axis.PixelMin) pMin.x = x_axis.PixelMin;
+ if (pMax.x < x_axis.PixelMin) pMax.x = x_axis.PixelMin;
+ if (pMin.x > x_axis.PixelMax) pMin.x = x_axis.PixelMax;
+ if (pMax.x > x_axis.PixelMax) pMax.x = x_axis.PixelMax;
//plot a rectangle that extends up to x2 with y1 height
if ((pMax.x > pMin.x) && (gp.CurrentPlot->PlotRect.Contains(pMin) || gp.CurrentPlot->PlotRect.Contains(pMax))) {
// ImVec4 colAlpha = item->Color;
@@ -2175,7 +2340,7 @@ inline void PlotDigitalEx(const char* label_id, Getter getter) {
template <typename T>
void PlotDigital(const char* label_id, const T* xs, const T* ys, int count, int offset, int stride) {
- GetterXsYs<T> getter(xs,ys,count,offset,stride);
+ GetterXY<GetterIdx<T>,GetterIdx<T>> getter(GetterIdx<T>(xs,count,offset,stride),GetterIdx<T>(ys,count,offset,stride),count);
return PlotDigitalEx(label_id, getter);
}
@@ -2191,8 +2356,8 @@ template IMPLOT_API void PlotDigital<float>(const char* label_id, const float* x
template IMPLOT_API void PlotDigital<double>(const char* label_id, const double* xs, const double* ys, int count, int offset, int stride);
// custom
-void PlotDigitalG(const char* label_id, ImPlotPoint (*getter_func)(void* data, int idx), void* data, int count, int offset) {
- GetterFuncPtr getter(getter_func,data,count,offset);
+void PlotDigitalG(const char* label_id, ImPlotGetter getter_func, void* data, int count) {
+ GetterFuncPtr getter(getter_func,data,count);
return PlotDigitalEx(label_id, getter);
}
@@ -2209,8 +2374,8 @@ void PlotImage(const char* label_id, ImTextureID user_texture_id, const ImPlotPo
ImU32 tint_col32 = ImGui::ColorConvertFloat4ToU32(tint_col);
GetCurrentItem()->Color = tint_col32;
ImDrawList& DrawList = *GetPlotDrawList();
- ImVec2 p1 = PlotToPixels(bmin.x, bmax.y);
- ImVec2 p2 = PlotToPixels(bmax.x, bmin.y);
+ ImVec2 p1 = PlotToPixels(bmin.x, bmax.y,IMPLOT_AUTO,IMPLOT_AUTO);
+ ImVec2 p2 = PlotToPixels(bmax.x, bmin.y,IMPLOT_AUTO,IMPLOT_AUTO);
PushPlotClipRect();
DrawList.AddImage(user_texture_id, p1, p2, uv0, uv1, tint_col32);
PopPlotClipRect();
@@ -2225,16 +2390,27 @@ void PlotImage(const char* label_id, ImTextureID user_texture_id, const ImPlotPo
// double
void PlotText(const char* text, double x, double y, bool vertical, const ImVec2& pixel_offset) {
IM_ASSERT_USER_ERROR(GImPlot->CurrentPlot != NULL, "PlotText() needs to be called between BeginPlot() and EndPlot()!");
+ SetupLock();
ImDrawList & DrawList = *GetPlotDrawList();
PushPlotClipRect();
ImU32 colTxt = GetStyleColorU32(ImPlotCol_InlayText);
if (vertical) {
- ImVec2 ctr = CalcTextSizeVertical(text) * 0.5f;
- ImVec2 pos = PlotToPixels(ImPlotPoint(x,y)) + ImVec2(-ctr.x, ctr.y) + pixel_offset;
+ ImVec2 siz = CalcTextSizeVertical(text) * 0.5f;
+ ImVec2 ctr = siz * 0.5f;
+ ImVec2 pos = PlotToPixels(ImPlotPoint(x,y),IMPLOT_AUTO,IMPLOT_AUTO) + ImVec2(-ctr.x, ctr.y) + pixel_offset;
+ if (FitThisFrame()) {
+ FitPoint(PixelsToPlot(pos));
+ FitPoint(PixelsToPlot(pos.x + siz.x, pos.y - siz.y));
+ }
AddTextVertical(&DrawList, pos, colTxt, text);
}
else {
- ImVec2 pos = PlotToPixels(ImPlotPoint(x,y)) - ImGui::CalcTextSize(text) * 0.5f + pixel_offset;
+ ImVec2 siz = ImGui::CalcTextSize(text);
+ ImVec2 pos = PlotToPixels(ImPlotPoint(x,y),IMPLOT_AUTO,IMPLOT_AUTO) - siz * 0.5f + pixel_offset;
+ if (FitThisFrame()) {
+ FitPoint(PixelsToPlot(pos));
+ FitPoint(PixelsToPlot(pos+siz));
+ }
DrawList.AddText(pos, colTxt, text);
}
PopPlotClipRect();
@@ -2249,4 +2425,4 @@ void PlotDummy(const char* label_id) {
EndItem();
}
-} // namespace ImPlot \ No newline at end of file
+} // namespace ImPlot