Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 88 additions & 0 deletions implot.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4556,6 +4556,94 @@ ImPlotMarker NextMarker() {
++gp.CurrentItems->MarkerIdx;
return idx;
}

void LoadDefaultLineStyles() {
const ImU32 Dash[] = {10, 6};
const ImU32 Dot[] = {2, 6};
const ImU32 DashDot[] = {10, 6, 2, 6};
const ImU32 DashDotDot[] = {10, 6, 2, 6, 2, 6};

// The default line styles are added at fixed indices
// We use the internal add function with the desired index to ensure they are stored in the correct order and that user defined line styles are added after them
AddLineStyleInternal(ImPlotLineStyle_Dashed, Dash, sizeof(Dash)/sizeof(ImU32));
AddLineStyleInternal(ImPlotLineStyle_Dotted, Dot, sizeof(Dot)/sizeof(ImU32));
AddLineStyleInternal(ImPlotLineStyle_DashDot, DashDot, sizeof(DashDot)/sizeof(ImU32));
AddLineStyleInternal(ImPlotLineStyle_DashDotDot, DashDotDot, sizeof(DashDotDot)/sizeof(ImU32));
}

int AddLineStyle(const ImU32* keys, int count) {
IM_ASSERT_USER_ERROR(count > 1 && count % 2 == 0, "The line style size must be greater than 1 and even!");
// User defined line styles are added after the default line styles, so we start with an index of -1 to append to the end of the list
return AddLineStyleInternal(-1, keys, count);
}

int AddLineStyleInternal(const int ID, const ImU32* keys, const int count) {
IM_ASSERT(ID < ImPlotLineStyle_COUNT || ID == -1); // ID must be a valid default line style index or -1 for user defined styles
ImPlotContext& gp = *GImPlot;
int period = 0;
for (int i = 0; i < count; ++i){
period += keys[i];
}
// Reserve space for default line styles if they haven't been added yet
if (gp.LineStyleData.Size < ImPlotLineStyle_COUNT) {
gp.LineStyleData.resize(ImPlotLineStyle_COUNT);
for (int i = 0; i < ImPlotLineStyle_COUNT; ++i) gp.LineStyleData[i].RectID = -1;
}
if (ID >= 0 && gp.LineStyleData[ID].RectID != -1)
return ID; // If the ID is already used
// Get font atlas and add a custom rectangle to it
ImFontAtlas *atlas = ImGui::GetIO().Fonts;
ImFontAtlasRectId rectID = atlas->AddCustomRect(510, 1);
int keyIdx = 0;
ImU32 k = 0;
ImU32 color = ~0;
if (rectID != -1)
{
// Build the atlas and get the pixel data
unsigned char* pixels;
int width, height;
atlas->GetTexDataAsRGBA32(&pixels, &width, &height);
// Retrieve the rectangle location and fill it with data
ImFontAtlasRect rect;
if (atlas->GetCustomRect(rectID, &rect))
{
for (int i = 0; i < rect.h; i++)
{
// Calculate the pointer to the start of the row in the atlas
ImU32* row = (ImU32*)pixels + (rect.y + i) * width + rect.x;
for (int j = 0; j < rect.w; j++)
{
row[j] = color;
if (++k >= keys[keyIdx]) {
color = ~color;
keyIdx = (keyIdx + 1) % count;
k = 0;
}
}
}
// Add the line style data to the context
if (ID < 0)
gp.LineStyleData.push_back(ImPlotLineStyleData(rectID, period, 510));
else
gp.LineStyleData[ID] = ImPlotLineStyleData(rectID, period, 510);
return gp.LineStyleData.Size - 1;
}
else
IM_ASSERT(0 && "Failed to retrieve custom rectangle from font atlas for line style!");
}
else
IM_ASSERT(0 && "Failed to add custom rectangle to font atlas for line style!");
return -1;
}

const ImPlotLineStyleData& GetLineStyleData(ImPlotLineStyle style) {
ImPlotContext& gp = *GImPlot;
IM_ASSERT_USER_ERROR(style >= 0 && style < gp.LineStyleData.Size, "Invalid line style index!");
const ImPlotLineStyleData& data = gp.LineStyleData[style];
if (!ImGui::GetIO().Fonts->GetCustomRect(data.RectID, &data.Rect))
IM_ASSERT(0 && "Failed to retrieve custom rectangle from font atlas for line style!");
return data;
}

//------------------------------------------------------------------------------
// [Section] Colormaps
Expand Down
19 changes: 19 additions & 0 deletions implot.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ typedef int ImPlotCond; // -> enum ImPlotCond_
typedef int ImPlotCol; // -> enum ImPlotCol_
typedef int ImPlotStyleVar; // -> enum ImPlotStyleVar_
typedef int ImPlotScale; // -> enum ImPlotScale_
typedef int ImPlotLineStyle; // -> enum ImPlotLineStyle_
typedef int ImPlotMarker; // -> enum ImPlotMarker_
typedef int ImPlotColormap; // -> enum ImPlotColormap_
typedef int ImPlotLocation; // -> enum ImPlotLocation_
Expand All @@ -139,6 +140,7 @@ enum ImAxis_ {
enum ImPlotProp_ {
ImPlotProp_LineColor, // line color (applies to lines, bar edges); IMPLOT_AUTO_COL will use next Colormap color or current item color
ImPlotProp_LineWeight, // line weight in pixels (applies to lines, bar edges, marker edges)
ImPlotProp_LineStyle, // line style (applies to lines)
ImPlotProp_FillColor, // fill color (applies to shaded regions, bar faces); IMPLOT_AUTO_COL will use next Colormap color or current item color
ImPlotProp_FillAlpha, // alpha multiplier (applies to FillColor and MarkerFillColor)
ImPlotProp_Marker, // marker type; specify ImPlotMarker_Auto to use the next unused marker
Expand Down Expand Up @@ -429,6 +431,16 @@ enum ImPlotScale_ {
ImPlotScale_SymLog, // symmetric log scale
};

// Line style specifications.
enum ImPlotLineStyle_ {
ImPlotLineStyle_Solid = -1,// default
ImPlotLineStyle_Dashed, // 6px on, 6px off
ImPlotLineStyle_Dotted, // 2px on, 6px off
ImPlotLineStyle_DashDot, // 6px on, 2px off, 2px on, 2px off
ImPlotLineStyle_DashDotDot,// 6px on, 2px off, 2px on, 2px off, 2px on, 2px off
ImPlotLineStyle_COUNT
};

// Marker specifications.
enum ImPlotMarker_ {
ImPlotMarker_None = -2, // no marker
Expand Down Expand Up @@ -510,6 +522,7 @@ enum ImPlotBin_ {
struct ImPlotSpec {
ImVec4 LineColor = IMPLOT_AUTO_COL; // line color (applies to lines, bar edges); IMPLOT_AUTO_COL will use next Colormap color or current item color
float LineWeight = 1.0f; // line weight in pixels (applies to lines, bar edges, marker edges)
ImPlotLineStyle LineStyle = ImPlotLineStyle_Solid; // line style (applies to lines)
ImVec4 FillColor = IMPLOT_AUTO_COL; // fill color (applies to shaded regions, bar faces); IMPLOT_AUTO_COL will use next Colormap color or current item color
float FillAlpha = 1.0f; // alpha multiplier (applies to FillColor and MarkerFillColor)
ImPlotMarker Marker = ImPlotMarker_None; // marker type; specify ImPlotMarker_Auto to use the next unused marker
Expand Down Expand Up @@ -544,6 +557,7 @@ struct ImPlotSpec {
switch (prop) {
case ImPlotProp_LineColor : LineColor = ImGui::ColorConvertU32ToFloat4((ImU32)v); return;
case ImPlotProp_LineWeight : LineWeight = (float)v; return;
case ImPlotProp_LineStyle : LineStyle = (ImPlotLineStyle)v; return;
case ImPlotProp_FillColor : FillColor = ImGui::ColorConvertU32ToFloat4((ImU32)v); return;
case ImPlotProp_FillAlpha : FillAlpha = (float)v; return;
case ImPlotProp_Marker : Marker = (ImPlotMarker)v; return;
Expand Down Expand Up @@ -1216,6 +1230,11 @@ IMPLOT_API const char* GetMarkerName(ImPlotMarker idx);
// Returns the next marker and advances the marker for the current plot. You need to call this between Begin/EndPlot!
IMPLOT_API ImPlotMarker NextMarker();

// Executes post-setup initialization
IMPLOT_API void LoadDefaultLineStyles();

IMPLOT_API int AddLineStyle(const ImU32* keys, int count);

//-----------------------------------------------------------------------------
// [SECTION] Colormaps
//-----------------------------------------------------------------------------
Expand Down
55 changes: 55 additions & 0 deletions implot_demo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1063,6 +1063,60 @@ void Demo_RealtimePlots() {

//-----------------------------------------------------------------------------

void Demo_LineStyles() {
IMGUI_DEMO_MARKER("Plots/Line Styles");
static ImPlotSpec spec;
static bool is_init = false;
static ImPlotLineStyle custom_style[2];
// Custom line styles are defined by an array of on/off lengths in pixels.
// The first element is the length of the dash, the second is the length of the gap, and so on.
static ImU32 styleA[] = {15, 6, 15, 6, 2, 6}; // dash, dash, dot
static ImU32 styleB[] = {20, 6, 10, 6}; // long dash, short dash

// ImPlot::LoadDefaultLineStyles() must be called before using line styles!
// It should be called once after context creation and backend initialization
// Called here for demo purposes, but you should call it in your initialization code.
if (!is_init) {
// Register custom line style before loading defaults
custom_style[0] = ImPlot::AddLineStyle(styleA, sizeof(styleA)/sizeof(ImU32));
// Load default line styles
ImPlot::LoadDefaultLineStyles();
// Register custom line style after loading defaults (order doesn't matter)
custom_style[1] = ImPlot::AddLineStyle(styleB, sizeof(styleB)/sizeof(ImU32));
is_init = true;
}
ImGui::DragFloat("Line Weight", &spec.LineWeight,0.05f,0.5f,32.0f,"%.2f px");

if (ImPlot::BeginPlot("##LineStyles", ImVec2(-1,0), ImPlotFlags_CanvasOnly)) {

ImPlot::SetupAxes(nullptr, nullptr, ImPlotAxisFlags_NoDecorations, ImPlotAxisFlags_NoDecorations);
ImPlot::SetupAxesLimits(0, 5, 0, 9);

ImS8 xs[2] = {1,4};
ImS8 ys[2] = {7,8};

// Line Styles
for (int m = 0; m < ImPlotLineStyle_COUNT; ++m) {
ImGui::PushID(m);
spec.LineStyle = (ImPlotLineStyle)m;
ImPlot::PlotLine("##Style", xs, ys, 2, spec);
ImGui::PopID();
ys[0]--; ys[1]--;
}
// Custom Line Styles
for (int m = 0; m < 2; ++m) {
ImGui::PushID(m);
spec.LineStyle = custom_style[m];
ImPlot::PlotLine("##Custom", xs, ys, 2, spec);
ImGui::PopID();
ys[0]--; ys[1]--;
}
ImPlot::EndPlot();
}
}

//-----------------------------------------------------------------------------

void Demo_MarkersAndText() {
IMGUI_DEMO_MARKER("Plots/Markers and Text");
static ImPlotSpec spec(ImPlotProp_Marker, ImPlotMarker_Auto);
Expand Down Expand Up @@ -2499,6 +2553,7 @@ void ShowDemoWindow(bool* p_open) {
DemoHeader("Histogram 2D", Demo_Histogram2D);
DemoHeader("Digital Plots", Demo_DigitalPlots);
DemoHeader("Images", Demo_Images);
DemoHeader("Line Styles", Demo_LineStyles);
DemoHeader("Markers and Text", Demo_MarkersAndText);
DemoHeader("NaN Values", Demo_NaNValues);
ImGui::EndTabItem();
Expand Down
31 changes: 26 additions & 5 deletions implot_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ template <typename T>
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 the modulo of x by y (assumes y != 0)
static inline double ImMod(double x, double y) { return fmod(x, y); }
// Returns true if val is NAN
static inline bool ImNan(double val) { return isnan(val); }
// Returns true if val is NAN or INFINITY
Expand Down Expand Up @@ -285,6 +287,18 @@ typedef void (*ImPlotLocator)(ImPlotTicker& ticker, const ImPlotRange& range, fl
// [SECTION] Structs
//-----------------------------------------------------------------------------

struct ImPlotLineStyleData {
ImPlotLineStyleData() {}
ImPlotLineStyleData(ImFontAtlasRectId rect_id, float period, float max_length) :
RectID(rect_id),
Period(period),
MaxLength(max_length) {}
ImFontAtlasRectId RectID; // texture atlas rect ID for line style
float Period; // period of line style in pixels
float MaxLength; // maximum length of line style in pixels
mutable ImFontAtlasRect Rect; // cached rectangle for line style (filled in on demand)
};

// Combined date/time format spec
struct ImPlotDateTimeSpec {
ImPlotDateTimeSpec() {}
Expand Down Expand Up @@ -1243,11 +1257,12 @@ struct ImPlotContext {
ImPlotTagCollection Tags;

// Style and Colormaps
ImPlotStyle Style;
ImVector<ImGuiColorMod> ColorModifiers;
ImVector<ImGuiStyleMod> StyleModifiers;
ImPlotColormapData ColormapData;
ImVector<ImPlotColormap> ColormapModifiers;
ImPlotStyle Style;
ImVector<ImGuiColorMod> ColorModifiers;
ImVector<ImGuiStyleMod> StyleModifiers;
ImPlotColormapData ColormapData;
ImVector<ImPlotColormap> ColormapModifiers;
ImVector<ImPlotLineStyleData> LineStyleData;

// Time
tm Tm;
Expand Down Expand Up @@ -1508,6 +1523,12 @@ IMPLOT_API ImU32 SampleColormapU32(float t, ImPlotColormap cmap);
// Render a colormap bar
IMPLOT_API void RenderColorBar(const ImU32* colors, int size, ImDrawList& DrawList, const ImRect& bounds, bool vert, bool reversed, bool continuous);

// Adds a line style with the given ID to ImPlot context. Set ID to -1 to add a line style with an automatically generated ID.
IMPLOT_API int AddLineStyleInternal(const int ID, const ImU32* keys, const int count);

// Returns line style data for a given line style. Do not store the returned value between frames as it may be invalidated if texture atlas is rebuilt.
IMPLOT_API const ImPlotLineStyleData& GetLineStyleData(ImPlotLineStyle style);

//-----------------------------------------------------------------------------
// [SECTION] Math and Misc Utils
//-----------------------------------------------------------------------------
Expand Down
Loading