1
0
Fork 0
mirror of https://github.com/gwm17/implot.git synced 2024-11-26 20:28:50 -05:00

internal refactors and demo improvements

This commit is contained in:
Evan Pezent 2020-06-04 00:11:43 -05:00
parent 43f78f62b9
commit a70bbe5cff
2 changed files with 184 additions and 169 deletions

View File

@ -254,23 +254,7 @@ struct ImPlotTick {
bool Labeled; bool Labeled;
}; };
struct ImPlotItem { /// Axis state information that must persist after EndPlot
ImPlotItem() {
Show = true;
Highlight = false;
Color = NextColor();
NameOffset = -1;
ID = 0;
}
~ImPlotItem() { ID = 0; }
bool Show;
bool Highlight;
ImVec4 Color;
int NameOffset;
ImGuiID ID;
};
/// Plot axis structure. You shouldn't need to construct this!
struct ImPlotAxis { struct ImPlotAxis {
ImPlotAxis() { ImPlotAxis() {
Dragging = false; Dragging = false;
@ -287,7 +271,64 @@ struct ImPlotAxis {
ImPlotAxisFlags Flags, PreviousFlags; ImPlotAxisFlags Flags, PreviousFlags;
}; };
/// Holds Plot state information that must persist between frames /// Axis state information only needed between BeginPlot/EndPlot
struct ImPlotAxisState {
ImPlotAxis* axis;
bool has_range;
ImGuiCond range_cond;
bool present;
int present_so_far;
bool invert;
bool lock_min;
bool lock_max;
bool lock;
ImPlotAxisState(ImPlotAxis& axis_in, bool has_range_in, ImGuiCond range_cond_in,
bool present_in, int previous_present)
: axis(&axis_in),
has_range(has_range_in),
range_cond(range_cond_in),
present(present_in),
present_so_far(previous_present + (present ? 1 : 0)),
invert(HasFlag(axis->Flags, ImPlotAxisFlags_Invert)),
lock_min(HasFlag(axis->Flags, ImPlotAxisFlags_LockMin) || (has_range && range_cond == ImGuiCond_Always)),
lock_max(HasFlag(axis->Flags, ImPlotAxisFlags_LockMax) || (has_range && range_cond == ImGuiCond_Always)),
lock(!present || ((lock_min && lock_max) || (has_range && range_cond == ImGuiCond_Always))) {}
ImPlotAxisState()
: axis(),
has_range(),
range_cond(),
present(),
present_so_far(),
invert(),
lock_min(),
lock_max(),
lock() {}
};
struct ImPlotAxisColor {
ImPlotAxisColor() : Major(), Minor(), Txt() {}
ImU32 Major, Minor, Txt;
};
/// State information for Plot items
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;
};
/// Holds Plot state information that must persist after EndPlot
struct ImPlotState { struct ImPlotState {
ImPlotState() { ImPlotState() {
Selecting = Querying = Queried = DraggingQuery = false; Selecting = Querying = Queried = DraggingQuery = false;
@ -393,12 +434,10 @@ struct ImPlotContext {
Col_Txt, Col_TxtDis, Col_Txt, Col_TxtDis,
Col_SlctBg, Col_SlctBd, Col_SlctBg, Col_SlctBd,
Col_QryBg, Col_QryBd; Col_QryBg, Col_QryBd;
struct AxisColor { ImPlotAxisColor Col_X;
AxisColor() : Major(), Minor(), Txt() {} ImPlotAxisColor Col_Y[MAX_Y_AXES];
ImU32 Major, Minor, Txt; ImPlotAxisState X;
}; ImPlotAxisState Y[MAX_Y_AXES];
AxisColor Col_X;
AxisColor Col_Y[MAX_Y_AXES];
// Tick marks // Tick marks
ImVector<ImPlotTick> XTicks, YTicks[MAX_Y_AXES]; ImVector<ImPlotTick> XTicks, YTicks[MAX_Y_AXES];
ImGuiTextBuffer XTickLabels, YTickLabels[MAX_Y_AXES]; ImGuiTextBuffer XTickLabels, YTickLabels[MAX_Y_AXES];
@ -720,42 +759,8 @@ inline void AddCustomTicks(const double* values, const char** labels, int n, ImV
} }
namespace { namespace {
struct AxisState {
ImPlotAxis* axis;
bool has_range;
ImGuiCond range_cond;
bool present;
int present_so_far;
bool flip;
bool lock_min;
bool lock_max;
bool lock;
AxisState(ImPlotAxis& axis_in, bool has_range_in, ImGuiCond range_cond_in, void UpdateAxisColor(int axis_flag, ImPlotAxisColor* col) {
bool present_in, int previous_present)
: axis(&axis_in),
has_range(has_range_in),
range_cond(range_cond_in),
present(present_in),
present_so_far(previous_present + (present ? 1 : 0)),
flip(HasFlag(axis->Flags, ImPlotAxisFlags_Invert)),
lock_min(HasFlag(axis->Flags, ImPlotAxisFlags_LockMin)),
lock_max(HasFlag(axis->Flags, ImPlotAxisFlags_LockMax)),
lock(present && ((lock_min && lock_max) || (has_range && range_cond == ImGuiCond_Always))) {}
AxisState()
: axis(),
has_range(),
range_cond(),
present(),
present_so_far(),
flip(),
lock_min(),
lock_max(),
lock() {}
};
void UpdateAxisColor(int axis_flag, ImPlotContext::AxisColor* 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]; 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->Major = ImGui::GetColorU32(col_Axis);
col->Minor = ImGui::GetColorU32(col_Axis * ImVec4(1, 1, 1, 0.25f)); col->Minor = ImGui::GetColorU32(col_Axis * ImVec4(1, 1, 1, 0.25f));
@ -772,16 +777,16 @@ struct ImPlotAxisScale {
class YPadCalculator { class YPadCalculator {
public: public:
YPadCalculator(const AxisState* axis_states, const float* max_label_widths, float txt_off) YPadCalculator(const ImPlotAxisState* axis_states, const float* max_label_widths, float txt_off)
: AxisStates(axis_states), MaxLabelWidths(max_label_widths), TxtOff(txt_off) {} : ImPlotAxisStates(axis_states), MaxLabelWidths(max_label_widths), TxtOff(txt_off) {}
float operator()(int y_axis) { float operator()(int y_axis) {
ImPlotState& plot = *gp.CurrentPlot; ImPlotState& plot = *gp.CurrentPlot;
if (!AxisStates[y_axis].present) { return 0; } if (!ImPlotAxisStates[y_axis].present) { return 0; }
// If we have more than 1 axis present before us, then we need // If we have more than 1 axis present before us, then we need
// extra space to account for our tick bar. // extra space to account for our tick bar.
float pad_result = 0; float pad_result = 0;
if (AxisStates[y_axis].present_so_far >= 3) { if (ImPlotAxisStates[y_axis].present_so_far >= 3) {
pad_result += 6.0f; pad_result += 6.0f;
} }
if (!HasFlag(plot.YAxis[y_axis].Flags, ImPlotAxisFlags_TickLabels)) { if (!HasFlag(plot.YAxis[y_axis].Flags, ImPlotAxisFlags_TickLabels)) {
@ -792,7 +797,7 @@ class YPadCalculator {
} }
private: private:
const AxisState* const AxisStates; const ImPlotAxisState* const ImPlotAxisStates;
const float* const MaxLabelWidths; const float* const MaxLabelWidths;
const float TxtOff; const float TxtOff;
}; };
@ -885,17 +890,14 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons
} }
// AXIS STATES ------------------------------------------------------------ // AXIS STATES ------------------------------------------------------------
AxisState x(plot.XAxis, gp.NextPlotData.HasXRange, gp.NextPlotData.XRangeCond, true, 0); gp.X = ImPlotAxisState(plot.XAxis, gp.NextPlotData.HasXRange, gp.NextPlotData.XRangeCond, true, 0);
AxisState y[MAX_Y_AXES]; gp.Y[0] = ImPlotAxisState(plot.YAxis[0], gp.NextPlotData.HasYRange[0], gp.NextPlotData.YRangeCond[0], true, 0);
y[0] = AxisState(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],
y[1] = AxisState(plot.YAxis[1], gp.NextPlotData.HasYRange[1], gp.NextPlotData.YRangeCond[1], HasFlag(plot.Flags, ImPlotFlags_YAxis2), gp.Y[0].present_so_far);
HasFlag(plot.Flags, ImPlotFlags_YAxis2), y[0].present_so_far); gp.Y[2] = ImPlotAxisState(plot.YAxis[2], gp.NextPlotData.HasYRange[2], gp.NextPlotData.YRangeCond[2],
y[2] = AxisState(plot.YAxis[2], gp.NextPlotData.HasYRange[2], gp.NextPlotData.YRangeCond[2], HasFlag(plot.Flags, ImPlotFlags_YAxis3), gp.Y[1].present_so_far);
HasFlag(plot.Flags, ImPlotFlags_YAxis3), y[1].present_so_far);
gp.LockPlot = x.lock && y[0].lock && gp.LockPlot = gp.X.lock && gp.Y[0].lock && gp.Y[1].lock && gp.Y[2].lock;
( HasFlag(plot.Flags, ImPlotFlags_YAxis2) ? y[1].lock : true ) &&
( HasFlag(plot.Flags, ImPlotFlags_YAxis3) ? y[2].lock : true );
// CONSTRAINTS ------------------------------------------------------------ // CONSTRAINTS ------------------------------------------------------------
@ -977,7 +979,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons
HasFlag(plot.XAxis.Flags, ImPlotAxisFlags_TickLabels)) && plot.XAxis.Divisions > 1; HasFlag(plot.XAxis.Flags, ImPlotAxisFlags_TickLabels)) && plot.XAxis.Divisions > 1;
for (int i = 0; i < MAX_Y_AXES; i++) { for (int i = 0; i < MAX_Y_AXES; i++) {
gp.RenderY[i] = gp.RenderY[i] =
y[i].present && gp.Y[i].present &&
(HasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_GridLines) || (HasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_GridLines) ||
HasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_TickMarks) || HasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_TickMarks) ||
HasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_TickLabels)) && plot.YAxis[i].Divisions > 1; HasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_TickLabels)) && plot.YAxis[i].Divisions > 1;
@ -998,7 +1000,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons
float max_label_width[MAX_Y_AXES] = {}; float max_label_width[MAX_Y_AXES] = {};
for (int i = 0; i < MAX_Y_AXES; i++) { for (int i = 0; i < MAX_Y_AXES; i++) {
if (y[i].present && HasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_TickLabels)) { if (gp.Y[i].present && HasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_TickLabels)) {
LabelTicks(gp.YTicks[i], HasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_Scientific), gp.YTickLabels[i]); LabelTicks(gp.YTicks[i], HasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_Scientific), gp.YTickLabels[i]);
for (int t = 0; t < gp.YTicks[i].Size; t++) { for (int t = 0; t < gp.YTicks[i].Size; t++) {
ImPlotTick *yt = &gp.YTicks[i][t]; ImPlotTick *yt = &gp.YTicks[i][t];
@ -1013,7 +1015,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons
const float txt_height = ImGui::GetTextLineHeight(); const float txt_height = ImGui::GetTextLineHeight();
const float pad_top = title_size.x > 0.0f ? txt_height + txt_off : 0; const float pad_top = title_size.x > 0.0f ? txt_height + txt_off : 0;
const float pad_bot = (HasFlag(plot.XAxis.Flags, ImPlotAxisFlags_TickLabels) ? txt_height + txt_off : 0) + (x_label ? txt_height + txt_off : 0); const float pad_bot = (HasFlag(plot.XAxis.Flags, ImPlotAxisFlags_TickLabels) ? txt_height + txt_off : 0) + (x_label ? txt_height + txt_off : 0);
YPadCalculator y_axis_pad(y, max_label_width, txt_off); YPadCalculator y_axis_pad(gp.Y, max_label_width, txt_off);
const float pad_left = y_axis_pad(0) + (y_label ? txt_height + txt_off : 0); const float pad_left = y_axis_pad(0) + (y_label ? txt_height + txt_off : 0);
const float pad_right = y_axis_pad(1) + y_axis_pad(2); const float pad_right = y_axis_pad(1) + y_axis_pad(2);
gp.BB_Grid = ImRect(gp.BB_Canvas.Min + ImVec2(pad_left, pad_top), gp.BB_Canvas.Max - ImVec2(pad_right, pad_bot)); gp.BB_Grid = ImRect(gp.BB_Canvas.Min + ImVec2(pad_left, pad_top), gp.BB_Canvas.Max - ImVec2(pad_right, pad_bot));
@ -1031,7 +1033,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons
// The third axis may be either referenced to the right of the // The third axis may be either referenced to the right of the
// bounding box, or 6 pixels further past the end of the 2nd axis. // bounding box, or 6 pixels further past the end of the 2nd axis.
gp.AxisLabelReference[2] = gp.AxisLabelReference[2] =
!y[1].present ? !gp.Y[1].present ?
gp.BB_Grid.Max.x : gp.BB_Grid.Max.x :
(gp.AxisLabelReference[1] + y_axis_pad(1) + 6); (gp.AxisLabelReference[1] + y_axis_pad(1) + 6);
@ -1047,9 +1049,9 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons
ImVec2(gp.BB_Grid.Max.x - 6, gp.BB_Grid.Max.y)); ImVec2(gp.BB_Grid.Max.x - 6, gp.BB_Grid.Max.y));
const bool hov_y_axis_region[MAX_Y_AXES] = { const bool hov_y_axis_region[MAX_Y_AXES] = {
y[0].present && (yAxisRegion_bb[0].Contains(IO.MousePos) || centralRegion.Contains(IO.MousePos)), gp.Y[0].present && (yAxisRegion_bb[0].Contains(IO.MousePos) || centralRegion.Contains(IO.MousePos)),
y[1].present && (yAxisRegion_bb[1].Contains(IO.MousePos) || centralRegion.Contains(IO.MousePos)), gp.Y[1].present && (yAxisRegion_bb[1].Contains(IO.MousePos) || centralRegion.Contains(IO.MousePos)),
y[2].present && (yAxisRegion_bb[2].Contains(IO.MousePos) || centralRegion.Contains(IO.MousePos)), gp.Y[2].present && (yAxisRegion_bb[2].Contains(IO.MousePos) || centralRegion.Contains(IO.MousePos)),
}; };
const bool any_hov_y_axis_region = hov_y_axis_region[0] || hov_y_axis_region[1] || hov_y_axis_region[2]; const bool any_hov_y_axis_region = hov_y_axis_region[0] || hov_y_axis_region[1] || hov_y_axis_region[2];
@ -1085,7 +1087,6 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons
// DRAG INPUT ------------------------------------------------------------- // DRAG INPUT -------------------------------------------------------------
// end drags // end drags
if (plot.XAxis.Dragging && (IO.MouseReleased[0] || !IO.MouseDown[0])) { if (plot.XAxis.Dragging && (IO.MouseReleased[0] || !IO.MouseDown[0])) {
plot.XAxis.Dragging = false; plot.XAxis.Dragging = false;
@ -1102,33 +1103,33 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons
// do drag // do drag
if (drag_in_progress) { if (drag_in_progress) {
UpdateTransformCache(); UpdateTransformCache();
if (!x.lock && plot.XAxis.Dragging) { if (!gp.X.lock && plot.XAxis.Dragging) {
ImPlotPoint plot_tl = PixelsToPlot(gp.BB_Grid.Min - IO.MouseDelta, 0); ImPlotPoint plot_tl = PixelsToPlot(gp.BB_Grid.Min - IO.MouseDelta, 0);
ImPlotPoint plot_br = PixelsToPlot(gp.BB_Grid.Max - IO.MouseDelta, 0); ImPlotPoint plot_br = PixelsToPlot(gp.BB_Grid.Max - IO.MouseDelta, 0);
if (!x.lock_min) if (!gp.X.lock_min)
plot.XAxis.Range.Min = x.flip ? plot_br.x : plot_tl.x; plot.XAxis.Range.Min = gp.X.invert ? plot_br.x : plot_tl.x;
if (!x.lock_max) if (!gp.X.lock_max)
plot.XAxis.Range.Max = x.flip ? plot_tl.x : plot_br.x; plot.XAxis.Range.Max = gp.X.invert ? plot_tl.x : plot_br.x;
} }
for (int i = 0; i < MAX_Y_AXES; i++) { for (int i = 0; i < MAX_Y_AXES; i++) {
if (!y[i].lock && plot.YAxis[i].Dragging) { if (!gp.Y[i].lock && plot.YAxis[i].Dragging) {
ImPlotPoint plot_tl = PixelsToPlot(gp.BB_Grid.Min - IO.MouseDelta, i); ImPlotPoint plot_tl = PixelsToPlot(gp.BB_Grid.Min - IO.MouseDelta, i);
ImPlotPoint plot_br = PixelsToPlot(gp.BB_Grid.Max - IO.MouseDelta, i); ImPlotPoint plot_br = PixelsToPlot(gp.BB_Grid.Max - IO.MouseDelta, i);
if (!y[i].lock_min) if (!gp.Y[i].lock_min)
plot.YAxis[i].Range.Min = y[i].flip ? plot_tl.y : plot_br.y; plot.YAxis[i].Range.Min = gp.Y[i].invert ? plot_tl.y : plot_br.y;
if (!y[i].lock_max) if (!gp.Y[i].lock_max)
plot.YAxis[i].Range.Max = y[i].flip ? plot_br.y : plot_tl.y; plot.YAxis[i].Range.Max = gp.Y[i].invert ? plot_br.y : plot_tl.y;
} }
} }
// Set the mouse cursor based on which axes are moving. // Set the mouse cursor based on which axes are moving.
int direction = 0; int direction = 0;
if (!x.lock && plot.XAxis.Dragging) { if (!gp.X.lock && plot.XAxis.Dragging) {
direction |= (1 << 1); direction |= (1 << 1);
} }
for (int i = 0; i < MAX_Y_AXES; i++) { for (int i = 0; i < MAX_Y_AXES; i++) {
if (!y[i].present) { continue; } if (!gp.Y[i].present) { continue; }
if (!y[i].lock && plot.YAxis[i].Dragging) { if (!gp.Y[i].lock && plot.YAxis[i].Dragging) {
direction |= (1 << 2); direction |= (1 << 2);
break; break;
} }
@ -1165,25 +1166,25 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons
zoom_rate = (-zoom_rate) / (1.0f + (2.0f * zoom_rate)); zoom_rate = (-zoom_rate) / (1.0f + (2.0f * zoom_rate));
float tx = Remap(IO.MousePos.x, gp.BB_Grid.Min.x, gp.BB_Grid.Max.x, 0.0f, 1.0f); float tx = Remap(IO.MousePos.x, gp.BB_Grid.Min.x, gp.BB_Grid.Max.x, 0.0f, 1.0f);
float ty = Remap(IO.MousePos.y, gp.BB_Grid.Min.y, gp.BB_Grid.Max.y, 0.0f, 1.0f); float ty = Remap(IO.MousePos.y, gp.BB_Grid.Min.y, gp.BB_Grid.Max.y, 0.0f, 1.0f);
if (hov_x_axis_region && !x.lock) { if (hov_x_axis_region && !gp.X.lock) {
ImPlotAxisScale axis_scale(0, tx, ty, zoom_rate); ImPlotAxisScale axis_scale(0, tx, ty, zoom_rate);
const ImPlotPoint& plot_tl = axis_scale.Min; const ImPlotPoint& plot_tl = axis_scale.Min;
const ImPlotPoint& plot_br = axis_scale.Max; const ImPlotPoint& plot_br = axis_scale.Max;
if (!x.lock_min) if (!gp.X.lock_min)
plot.XAxis.Range.Min = x.flip ? plot_br.x : plot_tl.x; plot.XAxis.Range.Min = gp.X.invert ? plot_br.x : plot_tl.x;
if (!x.lock_max) if (!gp.X.lock_max)
plot.XAxis.Range.Max = x.flip ? plot_tl.x : plot_br.x; plot.XAxis.Range.Max = gp.X.invert ? plot_tl.x : plot_br.x;
} }
for (int i = 0; i < MAX_Y_AXES; i++) { for (int i = 0; i < MAX_Y_AXES; i++) {
if (hov_y_axis_region[i] && !y[i].lock) { if (hov_y_axis_region[i] && !gp.Y[i].lock) {
ImPlotAxisScale axis_scale(i, tx, ty, zoom_rate); ImPlotAxisScale axis_scale(i, tx, ty, zoom_rate);
const ImPlotPoint& plot_tl = axis_scale.Min; const ImPlotPoint& plot_tl = axis_scale.Min;
const ImPlotPoint& plot_br = axis_scale.Max; const ImPlotPoint& plot_br = axis_scale.Max;
if (!y[i].lock_min) if (!gp.Y[i].lock_min)
plot.YAxis[i].Range.Min = y[i].flip ? plot_tl.y : plot_br.y; plot.YAxis[i].Range.Min = gp.Y[i].invert ? plot_tl.y : plot_br.y;
if (!y[i].lock_max) if (!gp.Y[i].lock_max)
plot.YAxis[i].Range.Max = y[i].flip ? plot_br.y : plot_tl.y; plot.YAxis[i].Range.Max = gp.Y[i].invert ? plot_br.y : plot_tl.y;
} }
} }
} }
@ -1197,16 +1198,16 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons
if (HasFlag(plot.Flags, ImPlotFlags_BoxSelect) && ImFabs(select_size.x) > 2 && ImFabs(select_size.y) > 2) { if (HasFlag(plot.Flags, ImPlotFlags_BoxSelect) && ImFabs(select_size.x) > 2 && ImFabs(select_size.y) > 2) {
ImPlotPoint p1 = PixelsToPlot(plot.SelectStart); ImPlotPoint p1 = PixelsToPlot(plot.SelectStart);
ImPlotPoint p2 = PixelsToPlot(IO.MousePos); ImPlotPoint p2 = PixelsToPlot(IO.MousePos);
if (!x.lock_min && !IO.KeyAlt) if (!gp.X.lock_min && !IO.KeyAlt)
plot.XAxis.Range.Min = ImMin(p1.x, p2.x); plot.XAxis.Range.Min = ImMin(p1.x, p2.x);
if (!x.lock_max && !IO.KeyAlt) if (!gp.X.lock_max && !IO.KeyAlt)
plot.XAxis.Range.Max = ImMax(p1.x, p2.x); plot.XAxis.Range.Max = ImMax(p1.x, p2.x);
for (int i = 0; i < MAX_Y_AXES; i++) { for (int i = 0; i < MAX_Y_AXES; i++) {
p1 = PixelsToPlot(plot.SelectStart, i); p1 = PixelsToPlot(plot.SelectStart, i);
p2 = PixelsToPlot(IO.MousePos, i); p2 = PixelsToPlot(IO.MousePos, i);
if (!y[i].lock_min && !IO.KeyShift) if (!gp.Y[i].lock_min && !IO.KeyShift)
plot.YAxis[i].Range.Min = ImMin(p1.y, p2.y); plot.YAxis[i].Range.Min = ImMin(p1.y, p2.y);
if (!y[i].lock_max && !IO.KeyShift) if (!gp.Y[i].lock_max && !IO.KeyShift)
plot.YAxis[i].Range.Max = ImMax(p1.y, p2.y); plot.YAxis[i].Range.Max = ImMax(p1.y, p2.y);
} }
} }
@ -1221,7 +1222,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons
plot.Selecting = false; plot.Selecting = false;
} }
// begin selection or query // begin selection or query
if (!gp.LockPlot && gp.Hov_Frame && gp.Hov_Grid && IO.MouseClicked[1]) { if (gp.Hov_Frame && gp.Hov_Grid && IO.MouseClicked[1]) {
plot.SelectStart = IO.MousePos; plot.SelectStart = IO.MousePos;
plot.Selecting = true; plot.Selecting = true;
} }
@ -1331,7 +1332,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons
} }
for (int i = 0; i < MAX_Y_AXES; i++) { for (int i = 0; i < MAX_Y_AXES; i++) {
if (y[i].present && HasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_GridLines)) { if (gp.Y[i].present && HasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_GridLines)) {
for (int t = 0; t < gp.YTicks[i].Size; t++) { for (int t = 0; t < gp.YTicks[i].Size; t++) {
ImPlotTick *yt = &gp.YTicks[i][t]; ImPlotTick *yt = &gp.YTicks[i][t];
DrawList.AddLine(ImVec2(gp.BB_Grid.Min.x, yt->PixelPos), ImVec2(gp.BB_Grid.Max.x, yt->PixelPos), yt->Major ? gp.Col_Y[i].Major : gp.Col_Y[i].Minor, 1); DrawList.AddLine(ImVec2(gp.BB_Grid.Min.x, yt->PixelPos), ImVec2(gp.BB_Grid.Max.x, yt->PixelPos), yt->Major ? gp.Col_Y[i].Major : gp.Col_Y[i].Minor, 1);
@ -1364,7 +1365,7 @@ bool BeginPlot(const char* title, const char* x_label, const char* y_label, cons
} }
ImGui::PushClipRect(gp.BB_Frame.Min, gp.BB_Frame.Max, true); ImGui::PushClipRect(gp.BB_Frame.Min, gp.BB_Frame.Max, true);
for (int i = 0; i < MAX_Y_AXES; i++) { for (int i = 0; i < MAX_Y_AXES; i++) {
if (y[i].present && HasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_TickLabels)) { if (gp.Y[i].present && HasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_TickLabels)) {
const float x_start = const float x_start =
gp.AxisLabelReference[i] + gp.AxisLabelReference[i] +
((i == 0) ? ((i == 0) ?
@ -1412,40 +1413,51 @@ bool DragFloat<float>(const char* label, float* v, float v_speed, float v_min, f
return ImGui::DragScalar(label, ImGuiDataType_Float, v, v_speed, &v_min, &v_max, "%.3f", 1); return ImGui::DragScalar(label, ImGuiDataType_Float, v, v_speed, &v_min, &v_max, "%.3f", 1);
} }
inline void AxisMenu(ImPlotAxis& Axis) { inline void BeginDisabledControls(bool cond) {
ImGui::PushItemWidth(75); if (cond) {
bool lock_min = HasFlag(Axis.Flags, ImPlotAxisFlags_LockMin); ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true);
bool lock_max = HasFlag(Axis.Flags, ImPlotAxisFlags_LockMax); ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.25f);
bool invert = HasFlag(Axis.Flags, ImPlotAxisFlags_Invert); }
}
inline void EndDisabledControls(bool cond) {
if (cond) {
ImGui::PopItemFlag();
ImGui::PopStyleVar();
}
}
inline void AxisMenu(ImPlotAxis& Axis, ImPlotAxisState& state) {
ImGui::PushItemWidth(75);
bool total_lock = state.has_range && state.range_cond == ImGuiCond_Always;
bool logscale = HasFlag(Axis.Flags, ImPlotAxisFlags_LogScale); bool logscale = HasFlag(Axis.Flags, ImPlotAxisFlags_LogScale);
bool grid = HasFlag(Axis.Flags, ImPlotAxisFlags_GridLines); bool grid = HasFlag(Axis.Flags, ImPlotAxisFlags_GridLines);
bool ticks = HasFlag(Axis.Flags, ImPlotAxisFlags_TickMarks); bool ticks = HasFlag(Axis.Flags, ImPlotAxisFlags_TickMarks);
bool labels = HasFlag(Axis.Flags, ImPlotAxisFlags_TickLabels); bool labels = HasFlag(Axis.Flags, ImPlotAxisFlags_TickLabels);
if (ImGui::Checkbox("##LockMin", &lock_min))
FlipFlag(Axis.Flags, ImPlotAxisFlags_LockMin);
ImGui::SameLine();
if (lock_min) {
ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true);
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.25f);
}
DragFloat("Min", &Axis.Range.Min, 0.01f + 0.01f * (float)Axis.Range.Size(), -HUGE_VAL, Axis.Range.Max - DBL_EPSILON);
if (lock_min) {
ImGui::PopItemFlag();
ImGui::PopStyleVar(); }
if (ImGui::Checkbox("##LockMax", &lock_max)) BeginDisabledControls(total_lock);
FlipFlag(Axis.Flags, ImPlotAxisFlags_LockMax); if (ImGui::Checkbox("##LockMin", &state.lock_min))
FlipFlag(Axis.Flags, ImPlotAxisFlags_LockMin);
EndDisabledControls(total_lock);
ImGui::SameLine(); ImGui::SameLine();
if (lock_max) { BeginDisabledControls(state.lock_min);
ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); DragFloat("Min", &Axis.Range.Min, 0.01f + 0.01f * (float)Axis.Range.Size(), -HUGE_VAL, Axis.Range.Max - DBL_EPSILON);
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.25f); } EndDisabledControls(state.lock_min);
BeginDisabledControls(total_lock);
if (ImGui::Checkbox("##LockMax", &state.lock_max))
FlipFlag(Axis.Flags, ImPlotAxisFlags_LockMax);
EndDisabledControls(total_lock);
ImGui::SameLine();
BeginDisabledControls(state.lock_max);
DragFloat("Max", &Axis.Range.Max, 0.01f + 0.01f * (float)Axis.Range.Size(), Axis.Range.Min + DBL_EPSILON, HUGE_VAL); DragFloat("Max", &Axis.Range.Max, 0.01f + 0.01f * (float)Axis.Range.Size(), Axis.Range.Min + DBL_EPSILON, HUGE_VAL);
if (lock_max) { EndDisabledControls(state.lock_max);
ImGui::PopItemFlag();
ImGui::PopStyleVar();
}
ImGui::Separator(); ImGui::Separator();
if (ImGui::Checkbox("Invert", &invert))
if (ImGui::Checkbox("Invert", &state.invert))
FlipFlag(Axis.Flags, ImPlotAxisFlags_Invert); FlipFlag(Axis.Flags, ImPlotAxisFlags_Invert);
if (ImGui::Checkbox("Log Scale", &logscale)) if (ImGui::Checkbox("Log Scale", &logscale))
FlipFlag(Axis.Flags, ImPlotAxisFlags_LogScale); FlipFlag(Axis.Flags, ImPlotAxisFlags_LogScale);
@ -1456,12 +1468,13 @@ inline void AxisMenu(ImPlotAxis& Axis) {
FlipFlag(Axis.Flags, ImPlotAxisFlags_TickMarks); FlipFlag(Axis.Flags, ImPlotAxisFlags_TickMarks);
if (ImGui::Checkbox("Labels", &labels)) if (ImGui::Checkbox("Labels", &labels))
FlipFlag(Axis.Flags, ImPlotAxisFlags_TickLabels); FlipFlag(Axis.Flags, ImPlotAxisFlags_TickLabels);
} }
void PlotContextMenu(ImPlotState& plot) { void PlotContextMenu(ImPlotState& plot) {
if (ImGui::BeginMenu("X-Axis")) { if (ImGui::BeginMenu("X-Axis")) {
ImGui::PushID("X"); ImGui::PushID("X");
AxisMenu(plot.XAxis); AxisMenu(plot.XAxis, gp.X);
ImGui::PopID(); ImGui::PopID();
ImGui::EndMenu(); ImGui::EndMenu();
} }
@ -1480,7 +1493,7 @@ void PlotContextMenu(ImPlotState& plot) {
} }
if (ImGui::BeginMenu(buf)) { if (ImGui::BeginMenu(buf)) {
ImGui::PushID(i); ImGui::PushID(i);
AxisMenu(plot.YAxis[i]); AxisMenu(plot.YAxis[i], gp.Y[i]);
ImGui::PopID(); ImGui::PopID();
ImGui::EndMenu(); ImGui::EndMenu();
} }
@ -1565,16 +1578,7 @@ void EndPlot() {
// AXIS STATES ------------------------------------------------------------ // AXIS STATES ------------------------------------------------------------
// TODO: Move this into gp to avoid repetition const bool any_y_locked = gp.Y[0].lock || gp.Y[1].present ? gp.Y[1].lock : false || gp.Y[2].present ? gp.Y[2].lock : false;
AxisState x(plot.XAxis, gp.NextPlotData.HasXRange, gp.NextPlotData.XRangeCond, true, 0);
AxisState y[MAX_Y_AXES];
y[0] = AxisState(plot.YAxis[0], gp.NextPlotData.HasYRange[0], gp.NextPlotData.YRangeCond[0], true, 0);
y[1] = AxisState(plot.YAxis[1], gp.NextPlotData.HasYRange[1], gp.NextPlotData.YRangeCond[1],
HasFlag(plot.Flags, ImPlotFlags_YAxis2), y[0].present_so_far);
y[2] = AxisState(plot.YAxis[2], gp.NextPlotData.HasYRange[2], gp.NextPlotData.YRangeCond[2],
HasFlag(plot.Flags, ImPlotFlags_YAxis3), y[1].present_so_far);
const bool any_y_locked = y[0].lock || y[1].lock || y[2].lock;
const bool any_y_dragging = plot.YAxis[0].Dragging || plot.YAxis[1].Dragging || plot.YAxis[2].Dragging; const bool any_y_dragging = plot.YAxis[0].Dragging || plot.YAxis[1].Dragging || plot.YAxis[2].Dragging;
@ -1593,7 +1597,7 @@ void EndPlot() {
ImGui::PushClipRect(gp.BB_Grid.Min, ImVec2(gp.BB_Frame.Max.x, gp.BB_Grid.Max.y), true); ImGui::PushClipRect(gp.BB_Grid.Min, ImVec2(gp.BB_Frame.Max.x, gp.BB_Grid.Max.y), true);
int axis_count = 0; int axis_count = 0;
for (int i = 0; i < MAX_Y_AXES; i++) { for (int i = 0; i < MAX_Y_AXES; i++) {
if (!y[i].present) { continue; } if (!gp.Y[i].present) { continue; }
axis_count++; axis_count++;
if (!HasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_TickMarks)) { continue; } if (!HasFlag(plot.YAxis[i].Flags, ImPlotAxisFlags_TickMarks)) { continue; }
@ -1632,7 +1636,7 @@ void EndPlot() {
DrawList.AddRectFilled(gp.BB_Grid.Min, gp.BB_Grid.Max, gp.Col_SlctBg); DrawList.AddRectFilled(gp.BB_Grid.Min, gp.BB_Grid.Max, gp.Col_SlctBg);
DrawList.AddRect( gp.BB_Grid.Min, gp.BB_Grid.Max, gp.Col_SlctBd); DrawList.AddRect( gp.BB_Grid.Min, gp.BB_Grid.Max, gp.Col_SlctBd);
} }
else if ((x.lock || IO.KeyAlt)) { else if ((gp.X.lock || IO.KeyAlt)) {
DrawList.AddRectFilled(ImVec2(gp.BB_Grid.Min.x, select_bb.Min.y), ImVec2(gp.BB_Grid.Max.x, select_bb.Max.y), gp.Col_SlctBg); DrawList.AddRectFilled(ImVec2(gp.BB_Grid.Min.x, select_bb.Min.y), ImVec2(gp.BB_Grid.Max.x, select_bb.Max.y), gp.Col_SlctBg);
DrawList.AddRect( ImVec2(gp.BB_Grid.Min.x, select_bb.Min.y), ImVec2(gp.BB_Grid.Max.x, select_bb.Max.y), gp.Col_SlctBd); DrawList.AddRect( ImVec2(gp.BB_Grid.Min.x, select_bb.Min.y), ImVec2(gp.BB_Grid.Max.x, select_bb.Max.y), gp.Col_SlctBd);
} }
@ -2402,6 +2406,12 @@ inline void PlotEx(const char* label_id, Getter getter, int count, int offset)
ImPlotPoint p = getter(i); ImPlotPoint p = getter(i);
FitPoint(p); FitPoint(p);
} }
if (rend_fill) {
ImPlotPoint p1 = getter(0);
ImPlotPoint p2 = getter(count - 1);
p1.y = 0; p2.y = 0;
FitPoint(p1); FitPoint(p2);
}
} }
PushPlotClipRect(); PushPlotClipRect();
// render fill // render fill

View File

@ -67,7 +67,7 @@ struct ScrollingData {
int Offset; int Offset;
ImVector<t_float2> Data; ImVector<t_float2> Data;
ScrollingData() { ScrollingData() {
MaxSize = 1000; MaxSize = 2000;
Offset = 0; Offset = 0;
Data.reserve(MaxSize); Data.reserve(MaxSize);
} }
@ -93,7 +93,7 @@ struct RollingData {
ImVector<t_float2> Data; ImVector<t_float2> Data;
RollingData() { RollingData() {
Span = 10.0f; Span = 10.0f;
Data.reserve(1000); Data.reserve(2000);
} }
void AddPoint(t_float x, t_float y) { void AddPoint(t_float x, t_float y) {
t_float xmod = Fmod(x, Span); t_float xmod = Fmod(x, Span);
@ -375,14 +375,20 @@ void ShowDemoWindow(bool* p_open) {
sdata2.AddPoint(t, mouse.y * 0.0005f); sdata2.AddPoint(t, mouse.y * 0.0005f);
rdata2.AddPoint(t, mouse.y * 0.0005f); rdata2.AddPoint(t, mouse.y * 0.0005f);
} }
ImPlot::SetNextPlotLimitsX(t - 10, t, paused ? ImGuiCond_Once : ImGuiCond_Always); static float history = 10.0f;
ImGui::SliderFloat("History",&history,1,30,"%.1f s");
rdata1.Span = history;
rdata2.Span = history;
ImPlot::SetNextPlotLimitsX(t - history, t, paused ? ImGuiCond_Once : ImGuiCond_Always);
static int rt_axis = ImPlotAxisFlags_Default & ~ImPlotAxisFlags_TickLabels; static int rt_axis = ImPlotAxisFlags_Default & ~ImPlotAxisFlags_TickLabels;
if (ImPlot::BeginPlot("##Scrolling", NULL, NULL, ImVec2(-1,150), ImPlotFlags_Default, rt_axis, rt_axis)) { if (ImPlot::BeginPlot("##Scrolling", NULL, NULL, ImVec2(-1,150), ImPlotFlags_Default, rt_axis, rt_axis | ImPlotAxisFlags_LockMin)) {
ImPlot::PlotLine("Data 1", &sdata1.Data[0].x, &sdata1.Data[0].y, sdata1.Data.size(), sdata1.Offset, 2 * sizeof(t_float)); ImPlot::PlotLine("Data 1", &sdata1.Data[0].x, &sdata1.Data[0].y, sdata1.Data.size(), sdata1.Offset, 2 * sizeof(t_float));
ImPlot::PushStyleColor(ImPlotCol_Fill, ImVec4(1,0,0,0.25f));
ImPlot::PlotLine("Data 2", &sdata2.Data[0].x, &sdata2.Data[0].y, sdata2.Data.size(), sdata2.Offset, 2 * sizeof(t_float)); ImPlot::PlotLine("Data 2", &sdata2.Data[0].x, &sdata2.Data[0].y, sdata2.Data.size(), sdata2.Offset, 2 * sizeof(t_float));
ImPlot::PopStyleColor();
ImPlot::EndPlot(); ImPlot::EndPlot();
} }
ImPlot::SetNextPlotLimitsX(0, 10, ImGuiCond_Always); ImPlot::SetNextPlotLimitsX(0, history, ImGuiCond_Always);
if (ImPlot::BeginPlot("##Rolling", NULL, NULL, ImVec2(-1,150), ImPlotFlags_Default, rt_axis, rt_axis)) { if (ImPlot::BeginPlot("##Rolling", NULL, NULL, ImVec2(-1,150), ImPlotFlags_Default, rt_axis, rt_axis)) {
ImPlot::PlotLine("Data 1", &rdata1.Data[0].x, &rdata1.Data[0].y, rdata1.Data.size(), 0, 2 * sizeof(t_float)); ImPlot::PlotLine("Data 1", &rdata1.Data[0].x, &rdata1.Data[0].y, rdata1.Data.size(), 0, 2 * sizeof(t_float));
ImPlot::PlotLine("Data 2", &rdata2.Data[0].x, &rdata2.Data[0].y, rdata2.Data.size(), 0, 2 * sizeof(t_float)); ImPlot::PlotLine("Data 2", &rdata2.Data[0].x, &rdata2.Data[0].y, rdata2.Data.size(), 0, 2 * sizeof(t_float));
@ -632,13 +638,14 @@ void ShowDemoWindow(bool* p_open) {
} }
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
if (ImGui::CollapsingHeader("Drag and Drop")) { if (ImGui::CollapsingHeader("Drag and Drop")) {
const int K_CHANNELS = 9;
srand((int)(10000000 * ImGui::GetTime())); srand((int)(10000000 * ImGui::GetTime()));
static bool paused = false; static bool paused = false;
static bool init = true; static bool init = true;
static ScrollingData data[10]; static ScrollingData data[K_CHANNELS];
static bool show[10]; static bool show[K_CHANNELS];
if (init) { if (init) {
for (int i = 0; i < 10; ++i) { for (int i = 0; i < K_CHANNELS; ++i) {
show[i] = false; show[i] = false;
} }
init = false; init = false;
@ -646,7 +653,7 @@ void ShowDemoWindow(bool* p_open) {
ImGui::BulletText("Drag data items from the left column onto the plot."); ImGui::BulletText("Drag data items from the left column onto the plot.");
ImGui::BeginGroup(); ImGui::BeginGroup();
if (ImGui::Button("Clear", ImVec2(100, 0))) { if (ImGui::Button("Clear", ImVec2(100, 0))) {
for (int i = 0; i < 10; ++i) { for (int i = 0; i < K_CHANNELS; ++i) {
show[i] = false; show[i] = false;
data[i].Data.shrink(0); data[i].Data.shrink(0);
data[i].Offset = 0; data[i].Offset = 0;
@ -655,8 +662,8 @@ void ShowDemoWindow(bool* p_open) {
if (ImGui::Button(paused ? "Resume" : "Pause", ImVec2(100,0))) if (ImGui::Button(paused ? "Resume" : "Pause", ImVec2(100,0)))
paused = !paused; paused = !paused;
ImGui::Separator(); ImGui::Separator();
for (int i = 0; i < 10; ++i) { for (int i = 0; i < K_CHANNELS; ++i) {
char label[8]; char label[K_CHANNELS];
sprintf(label, show[i] ? "data_%d*" : "data_%d", i); sprintf(label, show[i] ? "data_%d*" : "data_%d", i);
ImGui::Selectable(label, false, 0, ImVec2(100, 0)); ImGui::Selectable(label, false, 0, ImVec2(100, 0));
if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) { if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) {
@ -670,18 +677,16 @@ void ShowDemoWindow(bool* p_open) {
static t_float t = 0; static t_float t = 0;
if (!paused) { if (!paused) {
t += ImGui::GetIO().DeltaTime; t += ImGui::GetIO().DeltaTime;
for (int i = 0; i < 10; ++i) { for (int i = 0; i < K_CHANNELS; ++i) {
if (show[i]) if (show[i])
data[i].AddPoint(t, data[i].Data.empty() ? data[i].AddPoint(t, (i+1)*0.1f + RandomRange(-0.01f,0.01f));
0.25f + 0.5f * (t_float)rand() / t_float(RAND_MAX) :
data[i].Data.back().y + (0.005f + 0.0002f * (t_float)rand() / t_float(RAND_MAX)) * (-1 + 2 * (t_float)rand() / t_float(RAND_MAX)));
} }
} }
ImPlot::SetNextPlotLimitsX((double)t - 10, t, paused ? ImGuiCond_Once : ImGuiCond_Always); ImPlot::SetNextPlotLimitsX((double)t - 10, t, paused ? ImGuiCond_Once : ImGuiCond_Always);
if (ImPlot::BeginPlot("##DND")) { if (ImPlot::BeginPlot("##DND")) {
for (int i = 0; i < 10; ++i) { for (int i = 0; i < K_CHANNELS; ++i) {
if (show[i] && data[i].Data.size() > 0) { if (show[i] && data[i].Data.size() > 0) {
char label[8]; char label[K_CHANNELS];
sprintf(label, "data_%d", i); sprintf(label, "data_%d", i);
ImPlot::PlotLine(label, &data[i].Data[0].x, &data[i].Data[0].y, data[i].Data.size(), data[i].Offset, 2 * sizeof(t_float)); ImPlot::PlotLine(label, &data[i].Data[0].x, &data[i].Data[0].y, data[i].Data.size(), data[i].Offset, 2 * sizeof(t_float));
} }