implot.cpp 147.9 KB
Newer Older
Evan Pezent's avatar
Evan Pezent 已提交
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// MIT License

// Copyright (c) 2020 Evan Pezent

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

23
// ImPlot v0.3 WIP
24
25
26
27
28
29
30
31
32
33

/*

API BREAKING CHANGES
====================
Occasionally introducing changes that are breaking the API. We try to make the breakage minor and easy to fix.
Below is a change-log of API breaking changes only. If you are using one of the functions listed, expect to have to fix some code.
When you are not sure about a old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all implot files.
You can read releases logs https://github.com/epezent/implot/releases for more details.

34
- 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.
Evan Pezent's avatar
Evan Pezent 已提交
35
- 2020/06/01 (0.3) - SetPalette was changed to `SetColormap` for consistency with other plotting libraries. `RestorePalette` was removed. Use `SetColormap(ImPlotColormap_Default)`.
36
- 2020/05/31 (0.3) - Plot functions taking custom ImVec2* getters were removed. Use the ImPlotPoint* getter versions instead.
37
- 2020/05/29 (0.3) - The signature of ImPlotLimits::Contains was changed to take two doubles instead of ImVec2
38
- 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`
39
40
                     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.
41
42
- 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`
ozlb's avatar
ozlb 已提交
43
- 2020/05/11 (0.2) - The namespace ImGui:: was replaced with ImPlot::. As a result, the following additional changes were made:
44
                     - Functions that were prefixed or decorated with the word "Plot" have been truncated. E.g., `ImGui::PlotBars` is now just `ImPlot::Bar`.
ozlb's avatar
ozlb 已提交
45
                       It should be fairly obvious what was what.
Evan Pezent's avatar
Evan Pezent 已提交
46
47
                     - 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'.
48
49
50
- 2020/05/10 (0.2) - The following function/struct names were changes:
                    - ImPlotRange       -> ImPlotLimits
                    - GetPlotRange()    -> GetPlotLimits()
Evan Pezent's avatar
Evan Pezent 已提交
51
                    - SetNextPlotRange  -> SetNextPlotLimits
52
53
54
55
56
57
                    - 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.

*/

Evan Pezent's avatar
Evan Pezent 已提交
58
59
60
61
#ifndef IMGUI_DEFINE_MATH_OPERATORS
#define IMGUI_DEFINE_MATH_OPERATORS
#endif

62
63
64
65
66
#include "implot.h"
#include "imgui_internal.h"
#ifdef _MSC_VER
#define sprintf sprintf_s
#endif
Evan Pezent's avatar
Evan Pezent 已提交
67
68
69
70
71
72
73
74
75
76
77
78
79

#define IM_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;                                                                         \
        }                                                                                          \
    }

// Special Color used to specific that a plot item color should set determined automatically.
#define IM_COL_AUTO ImVec4(0,0,0,-1)
80
81
// The maximum number of support y-axes
#define MAX_Y_AXES 3
Evan Pezent's avatar
Evan Pezent 已提交
82

83
84
85
// static inline float  ImLog10(float x)  { return log10f(x); }
static inline double ImLog10(double x) { return log10(x); }

Evan Pezent's avatar
Evan Pezent 已提交
86
87
ImPlotStyle::ImPlotStyle() {
    LineWeight = 1;
88
    Marker = ImPlotMarker_None;
89
    MarkerSize = 4;
Evan Pezent's avatar
Evan Pezent 已提交
90
91
92
    MarkerWeight = 1;
    ErrorBarSize = 5;
    ErrorBarWeight = 1.5;
ozlb's avatar
ozlb 已提交
93
    DigitalBitHeight = 8;
94
    DigitalBitGap = 4;
Evan Pezent's avatar
Evan Pezent 已提交
95
96
97
98
99
100
101
102
103
104
105

    Colors[ImPlotCol_Line]          = IM_COL_AUTO;
    Colors[ImPlotCol_Fill]          = IM_COL_AUTO;
    Colors[ImPlotCol_MarkerOutline] = IM_COL_AUTO;
    Colors[ImPlotCol_MarkerFill]    = IM_COL_AUTO;
    Colors[ImPlotCol_ErrorBar]      = IM_COL_AUTO;
    Colors[ImPlotCol_FrameBg]       = IM_COL_AUTO;
    Colors[ImPlotCol_PlotBg]        = IM_COL_AUTO;
    Colors[ImPlotCol_PlotBorder]    = IM_COL_AUTO;
    Colors[ImPlotCol_XAxis]         = IM_COL_AUTO;
    Colors[ImPlotCol_YAxis]         = IM_COL_AUTO;
106
107
    Colors[ImPlotCol_YAxis2]        = IM_COL_AUTO;
    Colors[ImPlotCol_YAxis3]        = IM_COL_AUTO;
Evan Pezent's avatar
Evan Pezent 已提交
108
    Colors[ImPlotCol_Selection]     = ImVec4(1,1,0,1);
ozlb's avatar
Curors    
ozlb 已提交
109
    Colors[ImPlotCol_Query]         = ImVec4(0,1,0,1);
110
111
}

Evan Pezent's avatar
Evan Pezent 已提交
112
113
114
115
ImPlotRange::ImPlotRange() {
    Min = NAN;
    Max = NAN;
}
116

117
bool ImPlotRange::Contains(double v) const {
118
    return v >= Min && v <= Max;
119
120
}

121
double ImPlotRange::Size() const {
122
123
124
125
126
    return Max - Min;
}

ImPlotLimits::ImPlotLimits() {}

Evan Pezent's avatar
Evan Pezent 已提交
127
128
129
130
bool ImPlotLimits::Contains(const ImPlotPoint& p) const {
    return Contains(p.x, p.y);
}

131
132
bool ImPlotLimits::Contains(double x, double y) const {
    return X.Contains(x) && Y.Contains(y);
Evan Pezent's avatar
Evan Pezent 已提交
133
134
}

ozlb's avatar
ozlb 已提交
135
namespace ImPlot {
Evan Pezent's avatar
Evan Pezent 已提交
136
137
138

namespace {

139
140
141
//-----------------------------------------------------------------------------
// Private Utils
//-----------------------------------------------------------------------------
Evan Pezent's avatar
Evan Pezent 已提交
142

Evan Pezent's avatar
Evan Pezent 已提交
143
144
145
146
147
148
149
150
151
152
template <int Count>
struct OffsetCalculator {
    OffsetCalculator(int* sizes) {
        Offsets[0] = 0;
        for (int i = 1; i < Count; ++i)
            Offsets[i] = Offsets[i-1] + sizes[i-1];
    }
    int Offsets[Count];
};

Evan Pezent's avatar
Evan Pezent 已提交
153
154
155
156
157
158
159
160
161
template <typename T>
void FillRange(ImVector<T>& buffer, int n, T vmin, T vmax) {
    buffer.resize(n);
    T step = (vmax - vmin) / (n - 1);
    for (int i = 0; i < n; ++i) {
        buffer[i] = vmin + i * step;
    }
}

162
// Returns true if a flag is set
Evan Pezent's avatar
Evan Pezent 已提交
163
164
165
166
167
template <typename TSet, typename TFlag>
inline bool HasFlag(TSet set, TFlag flag) {
    return (set & flag) == flag;
}

168
// Flips a flag in a flagset
Evan Pezent's avatar
Evan Pezent 已提交
169
template <typename TSet, typename TFlag>
Evan Pezent's avatar
Evan Pezent 已提交
170
171
172
173
inline void FlipFlag(TSet& set, TFlag flag) {
    HasFlag(set, flag) ? set &= ~flag : set |= flag;
}

174
// Linearly remaps x from [x0 x1] to [y0 y1].
175
176
template <typename T>
inline T Remap(T x, T x0, T x1, T y0, T y1) {
Evan Pezent's avatar
Evan Pezent 已提交
177
178
179
    return y0 + (x - x0) * (y1 - y0) / (x1 - x0);
}

180
// Turns NANs to 0s
181
inline double ConstrainNan(double val) {
182
    return isnan(val) ? 0 : val;
Evan Pezent's avatar
Evan Pezent 已提交
183
184
}

185
// Turns infinity to floating point maximums
186
187
inline double ConstrainInf(double val) {
    return val == HUGE_VAL ?  DBL_MAX : val == -HUGE_VAL ? - DBL_MAX : val;
Evan Pezent's avatar
Evan Pezent 已提交
188
189
}

190
// Turns numbers less than or equal to 0 to 0.001 (sort of arbitrary, is there a better way?)
191
inline double ConstrainLog(double val) {
192
    return val <= 0 ? 0.001f : val;
Evan Pezent's avatar
Evan Pezent 已提交
193
194
}

195
// Returns true if val is NAN or INFINITY
196
197
inline bool NanOrInf(double val) {
    return val == HUGE_VAL || val == -HUGE_VAL || isnan(val);
Evan Pezent's avatar
Evan Pezent 已提交
198
199
}

200
201
202
203
204
205
206
207
208
209
210
// Computes order of magnitude of double.
// inline int OrderOfMagnitude(double val) {
//     return val == 0 ? 0 : (int)(floor(log10(fabs(val))));
// }

// Returns the precision required for a order of magnitude.
// inline int OrderToPrecision(int order) {
//     return order > 0 ? 0 : 1 - order;
// }

// Draws vertical text. The position is the bottom left of the text rect.
Evan Pezent's avatar
Evan Pezent 已提交
211
212
213
214
215
inline void AddTextVertical(ImDrawList *DrawList, const char *text, ImVec2 pos, ImU32 text_color) {
    pos.x                   = IM_ROUND(pos.x);
    pos.y                   = IM_ROUND(pos.y);
    ImFont *           font = GImGui->Font;
    const ImFontGlyph *glyph;
216
    for (char c = *text++; c; c = *text++) {
Evan Pezent's avatar
Evan Pezent 已提交
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
        glyph = font->FindGlyph(c);
        if (!glyph)
            continue;

        DrawList->PrimReserve(6, 4);
        DrawList->PrimQuadUV(
            pos + ImVec2(glyph->Y0, -glyph->X0), pos + ImVec2(glyph->Y0, -glyph->X1),
            pos + ImVec2(glyph->Y1, -glyph->X1), pos + ImVec2(glyph->Y1, -glyph->X0),

            ImVec2(glyph->U0, glyph->V0), ImVec2(glyph->U1, glyph->V0),
            ImVec2(glyph->U1, glyph->V1), ImVec2(glyph->U0, glyph->V1), text_color);
        pos.y -= glyph->AdvanceX;
    }
}

232
// Calculates the size of vertical text
Evan Pezent's avatar
Evan Pezent 已提交
233
inline ImVec2 CalcTextSizeVertical(const char *text) {
ozlb's avatar
ozlb 已提交
234
    ImVec2 sz = ImGui::CalcTextSize(text);
Evan Pezent's avatar
Evan Pezent 已提交
235
236
237
    return ImVec2(sz.y, sz.x);
}

238
239
240
241
242
243
244
245
246
} // private namespace

//-----------------------------------------------------------------------------
// Forwards
//-----------------------------------------------------------------------------

ImVec4 NextColor();

//-----------------------------------------------------------------------------
Evan Pezent's avatar
Evan Pezent 已提交
247
// Structs
248
249
//-----------------------------------------------------------------------------

250
// Tick mark info
251
252
struct ImPlotTick {
    ImPlotTick(double value, bool major, bool render_label = true) {
Evan Pezent's avatar
Evan Pezent 已提交
253
254
255
        PlotPos = value;
        Major = major;
        RenderLabel = render_label;
Evan Pezent's avatar
Evan Pezent 已提交
256
        Labeled = false;
Evan Pezent's avatar
Evan Pezent 已提交
257
    }
258
    double PlotPos;
Evan Pezent's avatar
Evan Pezent 已提交
259
260
    float  PixelPos;
    ImVec2 Size;
261
    int    TextOffset;
262
    bool   Major;
263
    bool   RenderLabel;
Evan Pezent's avatar
Evan Pezent 已提交
264
    bool   Labeled;
Evan Pezent's avatar
Evan Pezent 已提交
265
266
};

267
// Axis state information that must persist after EndPlot
Evan Pezent's avatar
Evan Pezent 已提交
268
struct ImPlotAxis {
Evan Pezent's avatar
Evan Pezent 已提交
269
    ImPlotAxis() {
Evan Pezent's avatar
Evan Pezent 已提交
270
        Dragging = false;
271
272
        Range.Min = 0;
        Range.Max = 1;
Evan Pezent's avatar
Evan Pezent 已提交
273
274
275
        Divisions = 3;
        Subdivisions = 10;
        Flags = PreviousFlags = ImPlotAxisFlags_Default;
Evan Pezent's avatar
Evan Pezent 已提交
276
277
    }
    bool Dragging;
278
    ImPlotRange Range;
Evan Pezent's avatar
Evan Pezent 已提交
279
280
    int Divisions;
    int Subdivisions;
281
    ImPlotAxisFlags Flags, PreviousFlags;
Evan Pezent's avatar
Evan Pezent 已提交
282
283
};

284
// Axis state information only needed between BeginPlot/EndPlot
285
struct ImPlotAxisState {
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
    ImPlotAxis* Axis;
    bool HasRange;
    ImGuiCond RangeCond;
    bool Present;
    int PresentSoFar;
    bool Invert;
    bool LockMin;
    bool LockMax;
    bool Lock;
    ImPlotAxisState(ImPlotAxis& axis, bool has_range, ImGuiCond range_cond, bool present, int previous_present) :
        Axis(&axis),
        HasRange(has_range),
        RangeCond(range_cond),
        Present(present),
        PresentSoFar(previous_present + (Present ? 1 : 0)),
        Invert(HasFlag(Axis->Flags, ImPlotAxisFlags_Invert)),
        LockMin(HasFlag(Axis->Flags, ImPlotAxisFlags_LockMin) || (HasRange && RangeCond == ImGuiCond_Always)),
        LockMax(HasFlag(Axis->Flags, ImPlotAxisFlags_LockMax) || (HasRange && RangeCond == ImGuiCond_Always)),
        Lock(!Present || ((LockMin && LockMax) || (HasRange && RangeCond == ImGuiCond_Always)))
    {}

    ImPlotAxisState() :
        Axis(), HasRange(), RangeCond(), Present(), PresentSoFar(),Invert(),LockMin(), LockMax(), Lock()
    {}
310
311
312
313
314
315
316
};

struct ImPlotAxisColor {
    ImPlotAxisColor() : Major(), Minor(), Txt() {}
    ImU32 Major, Minor, Txt;
};

317
// State information for Plot items
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
struct ImPlotItem {
    ImPlotItem() {
        Show = true;
        Highlight = false;
        Color = NextColor();
        NameOffset = -1;
        ID = 0;
    }
    ~ImPlotItem() { ID = 0; }
    bool Show;
    bool Highlight;
    ImVec4 Color;
    int NameOffset;
    ImGuiID ID;
};

334
// Holds Plot state information that must persist after EndPlot
ozlb's avatar
ozlb 已提交
335
336
struct ImPlotState {
    ImPlotState() {
337
        Selecting = Querying = Queried = DraggingQuery = false;
Evan Pezent's avatar
Evan Pezent 已提交
338
        SelectStart =  QueryStart = ImVec2(0,0);
339
        Flags = PreviousFlags = ImPlotFlags_Default;
Evan Pezent's avatar
Evan Pezent 已提交
340
        ColorIdx = 0;
341
        CurrentYAxis = 0;
Evan Pezent's avatar
Evan Pezent 已提交
342
343
344
345
346
    }
    ImPool<ImPlotItem> Items;

    ImRect BB_Legend;
    ImVec2 SelectStart;
347
    bool Selecting;
Evan Pezent's avatar
Evan Pezent 已提交
348
349
    bool Querying;
    bool Queried;
350
    bool DraggingQuery;
Evan Pezent's avatar
Evan Pezent 已提交
351
    ImVec2 QueryStart;
352
    ImRect QueryRect; // relative to BB_Plot!!
353

Evan Pezent's avatar
Evan Pezent 已提交
354
    ImPlotAxis XAxis;
355
356
357
    ImPlotAxis YAxis[MAX_Y_AXES];

    ImPlotFlags Flags, PreviousFlags;
Evan Pezent's avatar
Evan Pezent 已提交
358
    int ColorIdx;
359
    int CurrentYAxis;
Evan Pezent's avatar
Evan Pezent 已提交
360
361
};

362
363
364
struct ImPlotNextPlotData {
    ImPlotNextPlotData() {
        HasXRange = false;
Evan Pezent's avatar
Evan Pezent 已提交
365
        ShowDefaultTicksX = true;
366
367
        for (int i = 0; i < MAX_Y_AXES; ++i) {
            HasYRange[i] = false;
Evan Pezent's avatar
Evan Pezent 已提交
368
            ShowDefaultTicksY[i] = true;
369
370
        }
    }
Evan Pezent's avatar
Evan Pezent 已提交
371
    ImGuiCond XRangeCond;
372
    ImGuiCond YRangeCond[MAX_Y_AXES];
Evan Pezent's avatar
Evan Pezent 已提交
373
    bool HasXRange;
374
375
376
    bool HasYRange[MAX_Y_AXES];
    ImPlotRange X;
    ImPlotRange Y[MAX_Y_AXES];
Evan Pezent's avatar
Evan Pezent 已提交
377
378
    bool ShowDefaultTicksX;
    bool ShowDefaultTicksY[MAX_Y_AXES];
Evan Pezent's avatar
Evan Pezent 已提交
379
380
};

381
// Holds Plot state information that must persist only between calls to BeginPlot()/EndPlot()
Evan Pezent's avatar
Evan Pezent 已提交
382
struct ImPlotContext {
383
    ImPlotContext() : RenderX(), RenderY() {
Evan Pezent's avatar
Evan Pezent 已提交
384
385
        ChildWindowMade = false;
        Reset();
Evan Pezent's avatar
Evan Pezent 已提交
386
        SetColormap(ImPlotColormap_Default);
Evan Pezent's avatar
Evan Pezent 已提交
387
    }
388

Evan Pezent's avatar
Evan Pezent 已提交
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
    void Reset() {
        // end child window if it was made
        if (ChildWindowMade)
            ImGui::EndChild();
        ChildWindowMade = false;
        // reset the next plot data
        NextPlotData = ImPlotNextPlotData();
        // reset items count
        VisibleItemCount = 0;
        // reset legend items
        LegendIndices.shrink(0);
        LegendLabels.Buf.shrink(0);
        // reset ticks/labels
        XTicks.shrink(0);
        XTickLabels.Buf.shrink(0);
        for (int i = 0; i < 3; ++i) {
            YTicks[i].shrink(0);
            YTickLabels[i].Buf.shrink(0);
        }
        // reset extents
        FitX = false;
        ExtentsX.Min = HUGE_VAL;
        ExtentsX.Max = -HUGE_VAL;
        for (int i = 0; i < MAX_Y_AXES; i++) {
            ExtentsY[i].Min = HUGE_VAL;
            ExtentsY[i].Max = -HUGE_VAL;
            FitY[i] = false;
        }
        // reset digital plot items count
        DigitalPlotItemCnt = 0;
        DigitalPlotOffset = 0;
        // nullify plot
Evan Pezent's avatar
Evan Pezent 已提交
421
422
        CurrentPlot = NULL;
    }
423

424
    // ALl Plots
ozlb's avatar
ozlb 已提交
425
    ImPool<ImPlotState> Plots;
426
    // Current Plot
ozlb's avatar
ozlb 已提交
427
    ImPlotState* CurrentPlot;
Evan Pezent's avatar
Evan Pezent 已提交
428
    // Legend
Evan Pezent's avatar
Evan Pezent 已提交
429
    ImVector<int> LegendIndices;
430
    ImGuiTextBuffer LegendLabels;
Evan Pezent's avatar
Evan Pezent 已提交
431
    // Bounding regions
Evan Pezent's avatar
Evan Pezent 已提交
432
433
    ImRect BB_Frame;
    ImRect BB_Canvas;
434
    ImRect BB_Plot;
435
    // Cached Colors
Evan Pezent's avatar
Evan Pezent 已提交
436
437
    ImU32 Col_Frame, Col_Bg, Col_Border,
          Col_Txt, Col_TxtDis,
Evan Pezent's avatar
Evan Pezent 已提交
438
          Col_SlctBg, Col_SlctBd,
ozlb's avatar
ozlb 已提交
439
          Col_QryBg, Col_QryBd;
440
441
442
443
    ImPlotAxisColor Col_X;
    ImPlotAxisColor Col_Y[MAX_Y_AXES];
    ImPlotAxisState X;
    ImPlotAxisState Y[MAX_Y_AXES];
444
    // Tick marks
445
    ImVector<ImPlotTick> XTicks,  YTicks[MAX_Y_AXES];
446
447
    ImGuiTextBuffer XTickLabels, YTickLabels[MAX_Y_AXES];
    float AxisLabelReference[MAX_Y_AXES];
448
    // Transformation cache
449
450
    ImRect PixelRange[MAX_Y_AXES];
    // linear scale (slope)
451
452
    double Mx;
    double My[MAX_Y_AXES];
453
    // log scale denominator
454
455
    double LogDenX;
    double LogDenY[MAX_Y_AXES];
Evan Pezent's avatar
Evan Pezent 已提交
456
    // Data extents
457
458
    ImPlotRange ExtentsX;
    ImPlotRange ExtentsY[MAX_Y_AXES];
Evan Pezent's avatar
Evan Pezent 已提交
459
    int VisibleItemCount;
460
    bool FitThisFrame; bool FitX;
Evan Pezent's avatar
Evan Pezent 已提交
461
    bool FitY[MAX_Y_AXES];
462
463
    // Hover states
    bool Hov_Frame;
464
    bool Hov_Plot;
Evan Pezent's avatar
Evan Pezent 已提交
465
    // Render flags
466
    bool RenderX, RenderY[MAX_Y_AXES];
Evan Pezent's avatar
Evan Pezent 已提交
467
468
469
    // Lock info
    bool LockPlot;
    bool ChildWindowMade;
Evan Pezent's avatar
Evan Pezent 已提交
470
    // Mouse pos
Evan Pezent's avatar
Evan Pezent 已提交
471
    ImPlotPoint LastMousePos[MAX_Y_AXES];
Evan Pezent's avatar
Evan Pezent 已提交
472
    // Style
Evan Pezent's avatar
Evan Pezent 已提交
473
474
    ImVec4* Colormap;
    int     ColormapSize;
Evan Pezent's avatar
Evan Pezent 已提交
475
476
477
    ImPlotStyle Style;
    ImVector<ImGuiColorMod> ColorModifiers;  // Stack for PushStyleColor()/PopStyleColor()
    ImVector<ImGuiStyleMod> StyleModifiers;  // Stack for PushStyleVar()/PopStyleVar()
478
    ImPlotNextPlotData NextPlotData;
ozlb's avatar
ozlb 已提交
479
480
    // Digital plot item count
    int DigitalPlotItemCnt;
ozlb's avatar
ozlb 已提交
481
    int DigitalPlotOffset;
Evan Pezent's avatar
Evan Pezent 已提交
482
483
};

484
// Global plot context
Evan Pezent's avatar
Evan Pezent 已提交
485
486
static ImPlotContext gp;

487
//-----------------------------------------------------------------------------
Evan Pezent's avatar
Evan Pezent 已提交
488
// Context Utils
489
490
//-----------------------------------------------------------------------------

491
// Returns the next unused default plot color
492
ImVec4 NextColor() {
Evan Pezent's avatar
Evan Pezent 已提交
493
    ImVec4 col  = gp.Colormap[gp.CurrentPlot->ColorIdx % gp.ColormapSize];
494
495
    gp.CurrentPlot->ColorIdx++;
    return col;
496
}
Evan Pezent's avatar
Evan Pezent 已提交
497

Evan Pezent's avatar
Evan Pezent 已提交
498
inline void FitPoint(const ImPlotPoint& p) {
499
500
    ImPlotRange* extents_x = &gp.ExtentsX;
    ImPlotRange* extents_y = &gp.ExtentsY[gp.CurrentPlot->CurrentYAxis];
501
    if (!NanOrInf(p.x)) {
502
503
        extents_x->Min = p.x < extents_x->Min ? p.x : extents_x->Min;
        extents_x->Max = p.x > extents_x->Max ? p.x : extents_x->Max;
504
505
    }
    if (!NanOrInf(p.y)) {
506
507
        extents_y->Min = p.y < extents_y->Min ? p.y : extents_y->Min;
        extents_y->Max = p.y > extents_y->Max ? p.y : extents_y->Max;
508
509
510
511
512
513
514
515
516
    }
}

//-----------------------------------------------------------------------------
// Coordinate Transforms
//-----------------------------------------------------------------------------

inline void UpdateTransformCache() {
    // get pixels for transforms
517
    for (int i = 0; i < MAX_Y_AXES; i++) {
518
519
520
521
        gp.PixelRange[i] = ImRect(HasFlag(gp.CurrentPlot->XAxis.Flags, ImPlotAxisFlags_Invert) ? gp.BB_Plot.Max.x : gp.BB_Plot.Min.x,
                                  HasFlag(gp.CurrentPlot->YAxis[i].Flags, ImPlotAxisFlags_Invert) ? gp.BB_Plot.Min.y : gp.BB_Plot.Max.y,
                                  HasFlag(gp.CurrentPlot->XAxis.Flags, ImPlotAxisFlags_Invert) ? gp.BB_Plot.Min.x : gp.BB_Plot.Max.x,
                                  HasFlag(gp.CurrentPlot->YAxis[i].Flags, ImPlotAxisFlags_Invert) ? gp.BB_Plot.Max.y : gp.BB_Plot.Min.y);
522
523
524

        gp.My[i] = (gp.PixelRange[i].Max.y - gp.PixelRange[i].Min.y) / gp.CurrentPlot->YAxis[i].Range.Size();
    }
525
    gp.LogDenX = ImLog10(gp.CurrentPlot->XAxis.Range.Max / gp.CurrentPlot->XAxis.Range.Min);
526
    for (int i = 0; i < MAX_Y_AXES; i++) {
527
        gp.LogDenY[i] = ImLog10(gp.CurrentPlot->YAxis[i].Range.Max / gp.CurrentPlot->YAxis[i].Range.Min);
528
529
    }
    gp.Mx = (gp.PixelRange[0].Max.x - gp.PixelRange[0].Min.x) / gp.CurrentPlot->XAxis.Range.Size();
530
}
Evan Pezent's avatar
Evan Pezent 已提交
531

Evan Pezent's avatar
Evan Pezent 已提交
532
inline ImPlotPoint PixelsToPlot(float x, float y, int y_axis_in = -1) {
Evan Pezent's avatar
Evan Pezent 已提交
533
    IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "PixelsToPlot() needs to be called between BeginPlot() and EndPlot()!");
534
    const int y_axis = y_axis_in >= 0 ? y_axis_in : gp.CurrentPlot->CurrentYAxis;
Evan Pezent's avatar
Evan Pezent 已提交
535
    ImPlotPoint plt;
536
537
    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;
538
    if (HasFlag(gp.CurrentPlot->XAxis.Flags, ImPlotAxisFlags_LogScale)) {
539
540
        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;
541
    }
542
    if (HasFlag(gp.CurrentPlot->YAxis[y_axis].Flags, ImPlotAxisFlags_LogScale)) {
543
544
        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;
545
546
547
548
    }
    return plt;
}

Evan Pezent's avatar
Evan Pezent 已提交
549
ImPlotPoint PixelsToPlot(const ImVec2& pix, int y_axis) {
Evan Pezent's avatar
Evan Pezent 已提交
550
551
552
553
    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.
554
inline ImVec2 PlotToPixels(double x, double y, int y_axis_in = -1) {
Evan Pezent's avatar
Evan Pezent 已提交
555
    IM_ASSERT_USER_ERROR(gp.CurrentPlot != NULL, "PlotToPixels() needs to be called between BeginPlot() and EndPlot()!");
556
    const int y_axis = y_axis_in >= 0 ? y_axis_in : gp.CurrentPlot->CurrentYAxis;
557
    ImVec2 pix;
558
    if (HasFlag(gp.CurrentPlot->XAxis.Flags, ImPlotAxisFlags_LogScale)) {
559
        double t = ImLog10(x / gp.CurrentPlot->XAxis.Range.Min) / gp.LogDenX;
Evan Pezent's avatar
Evan Pezent 已提交
560
        x       = ImLerp(gp.CurrentPlot->XAxis.Range.Min, gp.CurrentPlot->XAxis.Range.Max, (float)t);
Evan Pezent's avatar
Evan Pezent 已提交
561
    }
562
    if (HasFlag(gp.CurrentPlot->YAxis[y_axis].Flags, ImPlotAxisFlags_LogScale)) {
563
        double t = ImLog10(y / gp.CurrentPlot->YAxis[y_axis].Range.Min) / gp.LogDenY[y_axis];
Evan Pezent's avatar
Evan Pezent 已提交
564
        y       = ImLerp(gp.CurrentPlot->YAxis[y_axis].Range.Min, gp.CurrentPlot->YAxis[y_axis].Range.Max, (float)t);
565
    }
Evan Pezent's avatar
Evan Pezent 已提交
566
567
    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));
568
569
570
    return pix;
}

Evan Pezent's avatar
Evan Pezent 已提交
571
// This function is convenient but should not be used to process a high volume of points. Use the Transformer structs below instead.
Evan Pezent's avatar
Evan Pezent 已提交
572
ImVec2 PlotToPixels(const ImPlotPoint& plt, int y_axis) {
573
    return PlotToPixels(plt.x, plt.y, y_axis);
574
575
}

576
// Transformer functors
Evan Pezent's avatar
Evan Pezent 已提交
577

578
struct TransformerLinLin {
579
    TransformerLinLin(int y_axis) : YAxis(y_axis) {}
580

581
    inline ImVec2 operator()(const ImPlotPoint& plt) { return (*this)(plt.x, plt.y); }
582
    inline ImVec2 operator()(double x, double y) {
583
584
        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)) );
585
586
    }

587
    int YAxis;
588
};
589

590
struct TransformerLogLin {
591
    TransformerLogLin(int y_axis) : YAxis(y_axis) {}
592

593
    inline ImVec2 operator()(const ImPlotPoint& plt) { return (*this)(plt.x, plt.y); }
594
595
    inline ImVec2 operator()(double x, double y) {
        double t = ImLog10(x / gp.CurrentPlot->XAxis.Range.Min) / gp.LogDenX;
Evan Pezent's avatar
Evan Pezent 已提交
596
        x        = ImLerp(gp.CurrentPlot->XAxis.Range.Min, gp.CurrentPlot->XAxis.Range.Max, (float)t);
597
598
        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)) );
599
    }
600

601
    int YAxis;
602
603
};

604
struct TransformerLinLog {
605
    TransformerLinLog(int y_axis) : YAxis(y_axis) {}
606

607
    inline ImVec2 operator()(const ImPlotPoint& plt) { return (*this)(plt.x, plt.y); }
608
    inline ImVec2 operator()(double x, double y) {
609
610
611
612
        double t = ImLog10(y / gp.CurrentPlot->YAxis[YAxis].Range.Min) / gp.LogDenY[YAxis];
        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)) );
613
    }
614
    int YAxis;
615
616
};

617
struct TransformerLogLog {
618
    TransformerLogLog(int y_axis) : YAxis(y_axis) {}
619
620

    inline ImVec2 operator()(const ImPlotPoint& plt) { return (*this)(plt.x, plt.y); }
621
622
623
    inline ImVec2 operator()(double x, double y) {
        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);
624
625
626
627
        t        = ImLog10(y / gp.CurrentPlot->YAxis[YAxis].Range.Min) / gp.LogDenY[YAxis];
        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)) );
628
    }
629

630
    int YAxis;
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
};

//-----------------------------------------------------------------------------
// Legend Utils
//-----------------------------------------------------------------------------

ImPlotItem* RegisterItem(const char* label_id) {
    ImGuiID id = ImGui::GetID(label_id);
    ImPlotItem* item = gp.CurrentPlot->Items.GetOrAddByKey(id);
    int idx = gp.CurrentPlot->Items.GetIndex(item);
    item->ID = id;
    gp.LegendIndices.push_back(idx);
    item->NameOffset = gp.LegendLabels.size();
    gp.LegendLabels.append(label_id, label_id + strlen(label_id) + 1);
    if (item->Show)
        gp.VisibleItemCount++;
    return item;
}

int GetLegendCount() {
    return gp.LegendIndices.size();
}

ImPlotItem* GetLegendItem(int i) {
    return gp.CurrentPlot->Items.GetByIndex(gp.LegendIndices[i]);
}

658
659
660
661
662
ImPlotItem* GetLegendItem(const char* label_id) {
    ImGuiID id = ImGui::GetID(label_id);
    return gp.CurrentPlot->Items.GetByKey(id);
}

663
664
665
666
667
668
669
const char* GetLegendLabel(int i) {
    ImPlotItem* item  = gp.CurrentPlot->Items.GetByIndex(gp.LegendIndices[i]);
    IM_ASSERT(item->NameOffset != -1 && item->NameOffset < gp.LegendLabels.Buf.Size);
    return gp.LegendLabels.Buf.Data + item->NameOffset;
}

//-----------------------------------------------------------------------------
Evan Pezent's avatar
Evan Pezent 已提交
670
// Tick Utils
671
//-----------------------------------------------------------------------------
Evan Pezent's avatar
Evan Pezent 已提交
672

673
674
// Utility function to that rounds x to powers of 2,5 and 10 for generating axis labels
// Taken from Graphics Gems 1 Chapter 11.2, "Nice Numbers for Graph Labels"
Evan Pezent's avatar
Evan Pezent 已提交
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
inline double NiceNum(double x, bool round) {
    double f;  /* fractional part of x */
    double nf; /* nice, rounded fraction */
    int expv = (int)floor(ImLog10(x));
    f = x / ImPow(10.0, (double)expv); /* between 1 and 10 */
    if (round)
        if (f < 1.5)
            nf = 1;
        else if (f < 3)
            nf = 2;
        else if (f < 7)
            nf = 5;
        else
            nf = 10;
    else if (f <= 1)
        nf = 1;
    else if (f <= 2)
        nf = 2;
    else if (f <= 5)
        nf = 5;
    else
        nf = 10;
    return nf * ImPow(10.0, expv);
}

Evan Pezent's avatar
Evan Pezent 已提交
700
inline void AddDefaultTicks(const ImPlotRange& range, int nMajor, int nMinor, bool logscale, ImVector<ImPlotTick> &out) {
Evan Pezent's avatar
Evan Pezent 已提交
701
    if (logscale) {
Evan Pezent's avatar
Evan Pezent 已提交
702
        if (range.Min <= 0 || range.Max <= 0)
Evan Pezent's avatar
Evan Pezent 已提交
703
            return;
704
705
        int exp_min = (int)ImLog10(range.Min);
        int exp_max = (int)(ceil(ImLog10(range.Max)));
Evan Pezent's avatar
Evan Pezent 已提交
706
707
708
709
        for (int e = exp_min - 1; e < exp_max + 1; ++e) {
            double major1 = ImPow(10, (double)(e));
            double major2 = ImPow(10, (double)(e + 1));
            double interval = (major2 - major1) / 9;
710
            if (major1 >= (range.Min - DBL_EPSILON) && major1 <= (range.Max + DBL_EPSILON))
711
                out.push_back(ImPlotTick(major1, true));
Evan Pezent's avatar
Evan Pezent 已提交
712
713
            for (int i = 1; i < 9; ++i) {
                double minor = major1 + i * interval;
714
                if (minor >= (range.Min - DBL_EPSILON) && minor <= (range.Max + DBL_EPSILON))
715
                    out.push_back(ImPlotTick(minor, false, false));
Evan Pezent's avatar
Evan Pezent 已提交
716
717
718
719
            }
        }
    }
    else {
Evan Pezent's avatar
Evan Pezent 已提交
720
721
722
723
        const double nice_range    = NiceNum(range.Size() * 0.99, 0);
        const double interval      = NiceNum(nice_range / (nMajor - 1), 1);
        const double graphmin      = floor(range.Min / interval) * interval;
        const double graphmax      = ceil(range.Max / interval) * interval;
Evan Pezent's avatar
Evan Pezent 已提交
724
        for (double major = graphmin; major < graphmax + 0.5 * interval; major += interval) {
Evan Pezent's avatar
Evan Pezent 已提交
725
            if (major >= range.Min && major <= range.Max)
726
                out.push_back(ImPlotTick(major, true));
Evan Pezent's avatar
Evan Pezent 已提交
727
728
            for (int i = 1; i < nMinor; ++i) {
                double minor = major + i * interval / nMinor;
Evan Pezent's avatar
Evan Pezent 已提交
729
                if (minor >= range.Min && minor <= range.Max)
730
                    out.push_back(ImPlotTick(minor, false));
Evan Pezent's avatar
Evan Pezent 已提交
731
732
733
734
735
            }
        }
    }
}

736
737
738
739
740
741
742
743
744
745
746
747
748
inline void AddCustomTicks(const double* values, const char** labels, int n, ImVector<ImPlotTick>& ticks, ImGuiTextBuffer& buffer) {
    for (int i = 0; i < n; ++i) {
        ImPlotTick tick(values[i],false);
        tick.TextOffset = buffer.size();
        if (labels != NULL) {
            buffer.append(labels[i], labels[i] + strlen(labels[i]) + 1);
            tick.Size = ImGui::CalcTextSize(labels[i]);
            tick.Labeled = true;
        }
        ticks.push_back(tick);
    }
}

749
inline void LabelTicks(ImVector<ImPlotTick> &ticks, bool scientific, ImGuiTextBuffer& buffer) {
Evan Pezent's avatar
Evan Pezent 已提交
750
    char temp[32];
ozlb's avatar
ozlb 已提交
751
    for (int t = 0; t < ticks.Size; t++) {
752
        ImPlotTick *tk = &ticks[t];
Evan Pezent's avatar
Evan Pezent 已提交
753
        if (tk->RenderLabel && !tk->Labeled) {
ozlb's avatar
ozlb 已提交
754
            tk->TextOffset = buffer.size();
Evan Pezent's avatar
Evan Pezent 已提交
755
            if (scientific)
ozlb's avatar
ozlb 已提交
756
                sprintf(temp, "%.0e", tk->PlotPos);
Evan Pezent's avatar
Evan Pezent 已提交
757
            else
758
                sprintf(temp, "%.10g", tk->PlotPos);
Evan Pezent's avatar
Evan Pezent 已提交
759
            buffer.append(temp, temp + strlen(temp) + 1);
ozlb's avatar
ozlb 已提交
760
            tk->Size = ImGui::CalcTextSize(buffer.Buf.Data + tk->TextOffset);
Evan Pezent's avatar
Evan Pezent 已提交
761
            tk->Labeled = true;
Evan Pezent's avatar
Evan Pezent 已提交
762
763
764
765
        }
    }
}

766
767
768
769
770
inline float MaxTickLabelWidth(ImVector<ImPlotTick>& ticks) {
    float w = 0;
    for (int i = 0; i < ticks.Size; ++i)
        w = ticks[i].Size.x > w ? ticks[i].Size.x : w;
    return w;
771
772
773
774
}

class YPadCalculator {
  public:
775
776
    YPadCalculator(const ImPlotAxisState* axis_states, const float* max_label_widths, float txt_off)
            : ImPlotAxisStates(axis_states), MaxLabelWidths(max_label_widths), TxtOff(txt_off) {}
777
778

    float operator()(int y_axis) {
ozlb's avatar
ozlb 已提交
779
        ImPlotState& plot = *gp.CurrentPlot;
780
        if (!ImPlotAxisStates[y_axis].Present) { return 0; }
781
782
783
        // If we have more than 1 axis present before us, then we need
        // extra space to account for our tick bar.
        float pad_result = 0;
784
        if (ImPlotAxisStates[y_axis].PresentSoFar >= 3) {
785
786
            pad_result += 6.0f;
        }
787
        if (!HasFlag(plot.YAxis[y_axis].Flags, ImPlotAxisFlags_TickLabels)) {
788
789
790
791
792
793
794
            return pad_result;
        }
        pad_result += MaxLabelWidths[y_axis] + TxtOff;
        return pad_result;
    }

  private:
795
    const ImPlotAxisState* const ImPlotAxisStates;
796
797
798
    const float* const MaxLabelWidths;
    const float TxtOff;
};
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817

//-----------------------------------------------------------------------------
// Axis Utils
//-----------------------------------------------------------------------------

void UpdateAxisColor(int axis_flag, ImPlotAxisColor* col) {
    const ImVec4 col_Axis = gp.Style.Colors[axis_flag].w == -1 ? ImGui::GetStyle().Colors[ImGuiCol_Text] * ImVec4(1, 1, 1, 0.25f) : gp.Style.Colors[axis_flag];
    col->Major = ImGui::GetColorU32(col_Axis);
    col->Minor = ImGui::GetColorU32(col_Axis * ImVec4(1, 1, 1, 0.25f));
    col->Txt   = ImGui::GetColorU32(ImVec4(col_Axis.x, col_Axis.y, col_Axis.z, 1));
}

struct ImPlotAxisScale {
    ImPlotAxisScale(int y_axis, float tx, float ty, float zoom_rate) {
        Min = PixelsToPlot(gp.BB_Plot.Min - gp.BB_Plot.GetSize() * ImVec2(tx * zoom_rate, ty * zoom_rate), y_axis);
        Max = PixelsToPlot(gp.BB_Plot.Max + gp.BB_Plot.GetSize() * ImVec2((1 - tx) * zoom_rate, (1 - ty) * zoom_rate), y_axis);
    }
    ImPlotPoint Min, Max;
};
818

819
//-----------------------------------------------------------------------------
Evan Pezent's avatar
Evan Pezent 已提交
820
// BeginPlot()
821
//-----------------------------------------------------------------------------
Evan Pezent's avatar
Evan Pezent 已提交
822

823
bool BeginPlot(const char* title, const char* x_label, const char* y_label, const ImVec2& size, ImPlotFlags flags, ImPlotAxisFlags x_flags, ImPlotAxisFlags y_flags, ImPlotAxisFlags y2_flags, ImPlotAxisFlags y3_flags) {
Evan Pezent's avatar
Evan Pezent 已提交
824
825
826
827
828
829
830
831

    IM_ASSERT_USER_ERROR(gp.CurrentPlot == NULL, "Mismatched BeginPlot()/EndPlot()!");

    // FRONT MATTER  -----------------------------------------------------------

    ImGuiContext &G      = *GImGui;
    ImGuiWindow * Window = G.CurrentWindow;
    if (Window->SkipItems) {
Evan Pezent's avatar
Evan Pezent 已提交
832
        gp.Reset();
Evan Pezent's avatar
Evan Pezent 已提交
833
834
835
836
837
        return false;
    }

    const ImGuiID     ID       = Window->GetID(title);
    const ImGuiStyle &Style    = G.Style;
Evan Pezent's avatar
Evan Pezent 已提交
838
    const ImGuiIO &   IO       = ImGui::GetIO();
Evan Pezent's avatar
Evan Pezent 已提交
839

Evan Pezent's avatar
Evan Pezent 已提交
840
    bool just_created = gp.Plots.GetByKey(ID) == NULL;
Evan Pezent's avatar
Evan Pezent 已提交
841
    gp.CurrentPlot = gp.Plots.GetOrAddByKey(ID);
ozlb's avatar
ozlb 已提交
842
    ImPlotState &plot = *gp.CurrentPlot;
Evan Pezent's avatar
Evan Pezent 已提交
843

844
845
    plot.CurrentYAxis = 0;

Evan Pezent's avatar
Evan Pezent 已提交
846
    if (just_created) {
847
848
849
850
851
        plot.Flags          = flags;
        plot.XAxis.Flags    = x_flags;
        plot.YAxis[0].Flags = y_flags;
        plot.YAxis[1].Flags = y2_flags;
        plot.YAxis[2].Flags = y3_flags;
Evan Pezent's avatar
Evan Pezent 已提交
852
    }
853
    else {
Evan Pezent's avatar
Evan Pezent 已提交
854
        // TODO: Check which individual flags changed, and only reset those!
855
        // There's probably an easy bit mask trick I'm not aware of.
Evan Pezent's avatar
Evan Pezent 已提交
856
857
        if (flags != plot.PreviousFlags)
            plot.Flags = flags;
858
859
860
861
862
863
864
865
866
867
868
869
870
        if (y_flags != plot.YAxis[0].PreviousFlags)
            plot.YAxis[0].PreviousFlags = y_flags;
        if (y2_flags != plot.YAxis[1].PreviousFlags)
            plot.YAxis[1].PreviousFlags = y2_flags;
        if (y3_flags != plot.YAxis[2].PreviousFlags)
            plot.YAxis[2].PreviousFlags = y3_flags;
    }

    plot.PreviousFlags          = flags;
    plot.XAxis.PreviousFlags    = x_flags;
    plot.YAxis[0].PreviousFlags = y_flags;
    plot.YAxis[1].PreviousFlags = y2_flags;
    plot.YAxis[2].PreviousFlags = y3_flags;
Evan Pezent's avatar
Evan Pezent 已提交
871

872
    // capture scroll with a child region
873
874
    const float default_w = 400;
    const float default_h = 300;
875
    if (!HasFlag(plot.Flags, ImPlotFlags_NoChild)) {
876
        ImGui::BeginChild(title, ImVec2(size.x == 0 ? default_w : size.x, size.y == 0 ? default_h : size.y));
877
878
        Window = ImGui::GetCurrentWindow();
        Window->ScrollMax.y = 1.0f;
Evan Pezent's avatar
Evan Pezent 已提交
879
880
881
882
        gp.ChildWindowMade = true;
    }
    else {
        gp.ChildWindowMade = false;
883
884
885
886
    }

    ImDrawList &DrawList = *Window->DrawList;

Evan Pezent's avatar
Evan Pezent 已提交
887
888
889
890
891
    // NextPlotData -----------------------------------------------------------

    if (gp.NextPlotData.HasXRange) {
        if (just_created || gp.NextPlotData.XRangeCond == ImGuiCond_Always)
        {
892
            plot.XAxis.Range = gp.NextPlotData.X;
Evan Pezent's avatar
Evan Pezent 已提交
893
894
895
        }
    }

896
897
898
899
900
901
    for (int i = 0; i < MAX_Y_AXES; i++) {
        if (gp.NextPlotData.HasYRange[i]) {
            if (just_created || gp.NextPlotData.YRangeCond[i] == ImGuiCond_Always)
            {
                plot.YAxis[i].Range = gp.NextPlotData.Y[i];
            }
Evan Pezent's avatar
Evan Pezent 已提交
902
903
904
905
        }
    }

    // AXIS STATES ------------------------------------------------------------
906
907
908
    gp.X    = ImPlotAxisState(plot.XAxis, gp.NextPlotData.HasXRange, gp.NextPlotData.XRangeCond, true, 0);
    gp.Y[0] = ImPlotAxisState(plot.YAxis[0], gp.NextPlotData.HasYRange[0], gp.NextPlotData.YRangeCond[0], true, 0);
    gp.Y[1] = ImPlotAxisState(plot.YAxis[1], gp.NextPlotData.HasYRange[1], gp.NextPlotData.YRangeCond[1],
909
                                   HasFlag(plot.Flags, ImPlotFlags_YAxis2), gp.Y[0].PresentSoFar);
910
    gp.Y[2] = ImPlotAxisState(plot.YAxis[2], gp.NextPlotData.HasYRange[2], gp.NextPlotData.YRangeCond[2],
911
                                   HasFlag(plot.Flags, ImPlotFlags_YAxis3), gp.Y[1].PresentSoFar);
912

913
    gp.LockPlot = gp.X.Lock && gp.Y[0].Lock && gp.Y[1].Lock && gp.Y[2].Lock;
Evan Pezent's avatar
Evan Pezent 已提交
914
915
916

    // CONSTRAINTS ------------------------------------------------------------

917
918
919
920
921
922
    plot.XAxis.Range.Min = ConstrainNan(ConstrainInf(plot.XAxis.Range.Min));
    plot.XAxis.Range.Max = ConstrainNan(ConstrainInf(plot.XAxis.Range.Max));
    for (int i = 0; i < MAX_Y_AXES; i++) {
        plot.YAxis[i].Range.Min = ConstrainNan(ConstrainInf(plot.YAxis[i].Range.Min));
        plot.YAxis[i].Range.Max = ConstrainNan(ConstrainInf(plot.YAxis[i].Range.Max));
    }
Evan Pezent's avatar
Evan Pezent 已提交
923

924
    if (HasFlag(plot.XAxis.Flags, ImPlotAxisFlags_LogScale))
925
        plot.XAxis.Range.Min = ConstrainLog(plot.XAxis.Range.Min);
926
    if (HasFlag(plot.XAxis.Flags, ImPlotAxisFlags_LogScale))
927
928
        plot.XAxis.Range.Max = ConstrainLog(plot.XAxis.Range.Max);
    for (int i = 0; i < MAX_Y_AXES; i++) {
929
        if (HasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_LogScale))
930
            plot.YAxis[i].Range.Min = ConstrainLog(plot.YAxis[i].Range.Min);
931
        if (HasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_LogScale))
932
933
            plot.YAxis[i].Range.Max = ConstrainLog(plot.YAxis[i].Range.Max);
    }
Evan Pezent's avatar
Evan Pezent 已提交
934

935
    if (plot.XAxis.Range.Max <= plot.XAxis.Range.Min)
936
        plot.XAxis.Range.Max = plot.XAxis.Range.Min + DBL_EPSILON;
937
938
    for (int i = 0; i < MAX_Y_AXES; i++) {
        if (plot.YAxis[i].Range.Max <= plot.YAxis[i].Range.Min)
939
            plot.YAxis[i].Range.Max = plot.YAxis[i].Range.Min + DBL_EPSILON;
940
    }
Evan Pezent's avatar
Evan Pezent 已提交
941
942

    // adaptive divisions
943
    if (HasFlag(plot.XAxis.Flags, ImPlotAxisFlags_Adaptive)) {
Evan Pezent's avatar
Evan Pezent 已提交
944
945
        plot.XAxis.Divisions = (int)IM_ROUND(0.003 * gp.BB_Canvas.GetWidth());
        if (plot.XAxis.Divisions < 2)
Evan Pezent's avatar
Evan Pezent 已提交
946
            plot.XAxis.Divisions = 2;
Evan Pezent's avatar
Evan Pezent 已提交
947
    }
948
    for (int i = 0; i < MAX_Y_AXES; i++) {
949
        if (HasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_Adaptive)) {
950
951
952
953
            plot.YAxis[i].Divisions = (int)IM_ROUND(0.003 * gp.BB_Canvas.GetHeight());
            if (plot.YAxis[i].Divisions < 2)
                plot.YAxis[i].Divisions = 2;
        }
Evan Pezent's avatar
Evan Pezent 已提交
954
955
956
957
    }

    // COLORS -----------------------------------------------------------------

ozlb's avatar
ozlb 已提交
958
959
960
    gp.Col_Frame  = gp.Style.Colors[ImPlotCol_FrameBg].w     == -1 ? ImGui::GetColorU32(ImGuiCol_FrameBg)    : ImGui::GetColorU32(gp.Style.Colors[ImPlotCol_FrameBg]);
    gp.Col_Bg     = gp.Style.Colors[ImPlotCol_PlotBg].w      == -1 ? ImGui::GetColorU32(ImGuiCol_WindowBg)   : ImGui::GetColorU32(gp.Style.Colors[ImPlotCol_PlotBg]);
    gp.Col_Border = gp.Style.Colors[ImPlotCol_PlotBorder].w  == -1 ? ImGui::GetColorU32(ImGuiCol_Text, 0.5f) : ImGui::GetColorU32(gp.Style.Colors[ImPlotCol_PlotBorder]);
Evan Pezent's avatar
Evan Pezent 已提交
961

962
963
964
965
    UpdateAxisColor(ImPlotCol_XAxis, &gp.Col_X);
    UpdateAxisColor(ImPlotCol_YAxis, &gp.Col_Y[0]);
    UpdateAxisColor(ImPlotCol_YAxis2, &gp.Col_Y[1]);
    UpdateAxisColor(ImPlotCol_YAxis3, &gp.Col_Y[2]);
Evan Pezent's avatar
Evan Pezent 已提交
966

ozlb's avatar
ozlb 已提交
967
968
969
970
971
972
    gp.Col_Txt    = ImGui::GetColorU32(ImGuiCol_Text);
    gp.Col_TxtDis = ImGui::GetColorU32(ImGuiCol_TextDisabled);
    gp.Col_SlctBg = ImGui::GetColorU32(gp.Style.Colors[ImPlotCol_Selection] * ImVec4(1,1,1,0.25f));
    gp.Col_SlctBd = ImGui::GetColorU32(gp.Style.Colors[ImPlotCol_Selection]);
    gp.Col_QryBg =  ImGui::GetColorU32(gp.Style.Colors[ImPlotCol_Query] * ImVec4(1,1,1,0.25f));
    gp.Col_QryBd =  ImGui::GetColorU32(gp.Style.Colors[ImPlotCol_Query]);
Evan Pezent's avatar
Evan Pezent 已提交
973
974
975
976

    // BB AND HOVER -----------------------------------------------------------

    // frame
977
    const ImVec2 frame_size = ImGui::CalcItemSize(size, default_w, default_h);
Evan Pezent's avatar
Evan Pezent 已提交
978
    gp.BB_Frame = ImRect(Window->DC.CursorPos, Window->DC.CursorPos + frame_size);
ozlb's avatar
ozlb 已提交
979
980
    ImGui::ItemSize(gp.BB_Frame);
    if (!ImGui::ItemAdd(gp.BB_Frame, 0, &gp.BB_Frame)) {
Evan Pezent's avatar
Evan Pezent 已提交
981
        gp.Reset();
Evan Pezent's avatar
Evan Pezent 已提交
982
983
        return false;
    }
ozlb's avatar
ozlb 已提交
984
985
    gp.Hov_Frame = ImGui::ItemHoverable(gp.BB_Frame, ID);
    ImGui::RenderFrame(gp.BB_Frame.Min, gp.BB_Frame.Max, gp.Col_Frame, true, Style.FrameRounding);
Evan Pezent's avatar
Evan Pezent 已提交
986
987

    // canvas bb
Evan Pezent's avatar
Evan Pezent 已提交
988
    gp.BB_Canvas = ImRect(gp.BB_Frame.Min + Style.WindowPadding, gp.BB_Frame.Max - Style.WindowPadding);
Evan Pezent's avatar
Evan Pezent 已提交
989

990
991
992
    gp.RenderX = (HasFlag(plot.XAxis.Flags, ImPlotAxisFlags_GridLines) ||
                    HasFlag(plot.XAxis.Flags, ImPlotAxisFlags_TickMarks) ||
                    HasFlag(plot.XAxis.Flags, ImPlotAxisFlags_TickLabels)) &&  plot.XAxis.Divisions > 1;
993
994
    for (int i = 0; i < MAX_Y_AXES; i++) {
        gp.RenderY[i] =
995
                gp.Y[i].Present &&
Evan Pezent's avatar
Evan Pezent 已提交
996
997
                (HasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_GridLines) ||
                 HasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_TickMarks) ||
998
                 HasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_TickLabels)) &&  plot.YAxis[i].Divisions > 1;
999
    }
Evan Pezent's avatar
Evan Pezent 已提交
1000

为了加快浏览速度,不会显示所有历史记录。 查看完整的 blame