-
-
Save sairus7/19778c05ffba7c677a3414f752a0f9cb to your computer and use it in GitHub Desktop.
ImPlot example with state-management and less boilerplate
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
include("Renderer.jl") | |
using .Renderer | |
using CImGui | |
using CImGui.CSyntax | |
using CImGui.CSyntax.CStatic | |
import CImGui.LibCImGui: ImGuiCond_Always, ImGuiCond_Once | |
using ImPlot | |
using UnPack | |
# GUI state | |
Base.@kwdef mutable struct MyStates | |
show_another_window = false | |
# make up some data | |
xs1 = Float64.(collect(1:100)) | |
ys1 = rand(6000) | |
noise = rand(length(xs1)) | |
bar_vals = Vector{Vector{Float64}}(undef, 5) | |
bar_maxes = zeros(5) | |
bar_mins = zeros(5) | |
bar_max = 0.0 | |
bar_min = 0.0 | |
bar_counter = 1 | |
shaded_x = 1:1000 | |
shaded_y1 = [sin(x) for x in range(0,2π, length = length(shaded_x))] | |
shaded_y_ref = -2.0 | |
end | |
# something that cannot be brought to MyStates constructor | |
function init(state::MyStates) | |
@unpack bar_vals, bar_maxes, bar_mins, shaded_x, shaded_y1 = state | |
for i in 1:length(bar_vals) | |
bar_vals[i] = Float64.(collect(range(rand(1:10), step=rand([-2,-1,1,2]), length=120))) | |
bar_maxes[i] = maximum(bar_vals[i]) | |
bar_mins[i] = minimum(bar_vals[i]) | |
end | |
state.bar_max = maximum(bar_maxes) | |
state.bar_min = minimum(bar_mins) | |
end | |
function update(state::MyStates) | |
@unpack show_another_window, xs1, ys1, noise, bar_vals, bar_maxes, bar_mins, bar_max, bar_min, bar_counter, | |
shaded_x, shaded_y1, shaded_y_ref = state | |
ys1 .= rand(6000) | |
noise .= xs1 .+ rand(-5.0:0.1:5.0, length(xs1)) | |
if bar_counter == 120 | |
state.bar_counter = 1 | |
else | |
state.bar_counter += 1 | |
end | |
end | |
# this is the UI function, whenever the structure of `MyStates` is changed, | |
function ui(state::MyStates) | |
@unpack show_another_window, xs1, ys1, noise, bar_vals, bar_maxes, bar_mins, bar_max, bar_min, bar_counter, | |
shaded_x, shaded_y1, shaded_y_ref = state | |
CImGui.Begin("Example Plots") | |
@c CImGui.Checkbox("Show Examples", &state.show_another_window) | |
CImGui.Text("Application average $(1000 / CImGui.GetIO().Framerate) ms/frame ($(CImGui.GetIO().Framerate) FPS)") | |
CImGui.End() | |
if state.show_another_window | |
@c CImGui.Begin("Examples Window", &state.show_another_window) | |
if CImGui.CollapsingHeader("Line plots") | |
ImPlot.SetNextPlotLimits(0.0, 6000, 0.0, 1.0, ImGuiCond_Always) | |
# Using '##' in the label name hides the plot label, but lets | |
# us keep the label ID unique for modifying styling etc. | |
if ImPlot.BeginPlot("##line", "x1", "y1", CImGui.ImVec2(-1,300)) | |
ImPlot.PlotLine(ys1) | |
ImPlot.EndPlot() | |
end | |
end | |
if CImGui.CollapsingHeader("Scatter plot") | |
ImPlot.SetNextPlotLimits(0,100,-5,105, ImGuiCond_Always) | |
if ImPlot.BeginPlot("##scatter", "x2", "y2", CImGui.ImVec2(-1,300)) | |
ImPlot.PlotScatter(xs1, noise) | |
ImPlot.EndPlot() | |
end | |
end | |
if CImGui.CollapsingHeader("Bar plot") | |
bar_val_step = [bar_vals[j][bar_counter] for j in 1:length(bar_vals)] | |
ImPlot.SetNextPlotLimits(-0.5, 4.5, bar_min, bar_max, ImGuiCond_Always) | |
if ImPlot.BeginPlot("##bars", "", "", CImGui.ImVec2(-1,300)) | |
ImPlot.PlotBars(bar_val_step) | |
ImPlot.EndPlot() | |
end | |
end | |
if CImGui.CollapsingHeader("Shaded plot") | |
ImPlot.SetNextPlotLimits(0,1000,-2,1, ImGuiCond_Always) | |
if ImPlot.BeginPlot("##shaded", "", "", CImGui.ImVec2(-1,300)) | |
ImPlot.PlotShaded(shaded_x, shaded_y1, shaded_y_ref) | |
ImPlot.EndPlot() | |
end | |
end | |
CImGui.End() | |
end | |
end | |
state = MyStates() | |
init(state) | |
update(state) # initial update | |
Renderer.render(()->ui(state), width = 360, height = 480, title = "A simple UI") | |
function infinite_loop(state::MyStates) | |
@async while true | |
update(state) | |
yield() | |
end | |
end | |
infinite_loop(state) # animate the plot |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Renderer | |
using CImGui | |
using CImGui.GLFWBackend | |
using CImGui.OpenGLBackend | |
using CImGui.GLFWBackend.GLFW | |
using CImGui.OpenGLBackend.ModernGL | |
function __init__() | |
@static if Sys.isapple() | |
# OpenGL 3.2 + GLSL 150 | |
global glsl_version = 150 | |
GLFW.WindowHint(GLFW.CONTEXT_VERSION_MAJOR, 3) | |
GLFW.WindowHint(GLFW.CONTEXT_VERSION_MINOR, 2) | |
GLFW.WindowHint(GLFW.OPENGL_PROFILE, GLFW.OPENGL_CORE_PROFILE) # 3.2+ only | |
GLFW.WindowHint(GLFW.OPENGL_FORWARD_COMPAT, GL_TRUE) # required on Mac | |
else | |
# OpenGL 3.0 + GLSL 130 | |
global glsl_version = 130 | |
GLFW.WindowHint(GLFW.CONTEXT_VERSION_MAJOR, 3) | |
GLFW.WindowHint(GLFW.CONTEXT_VERSION_MINOR, 0) | |
# GLFW.WindowHint(GLFW.OPENGL_PROFILE, GLFW.OPENGL_CORE_PROFILE) # 3.2+ only | |
# GLFW.WindowHint(GLFW.OPENGL_FORWARD_COMPAT, GL_TRUE) # 3.0+ only | |
end | |
end | |
error_callback(err::GLFW.GLFWError) = @error "GLFW ERROR: code $(err.code) msg: $(err.description)" | |
function init_renderer(width, height, title::AbstractString) | |
# setup GLFW error callback | |
GLFW.SetErrorCallback(error_callback) | |
# create window | |
window = GLFW.CreateWindow(width, height, title) | |
@assert window != C_NULL | |
GLFW.MakeContextCurrent(window) | |
GLFW.SwapInterval(1) # enable vsync | |
# setup Dear ImGui context | |
ctx = CImGui.CreateContext() | |
# setup Dear ImGui style | |
CImGui.StyleColorsDark() | |
# CImGui.StyleColorsClassic() | |
# CImGui.StyleColorsLight() | |
# setup Platform/Renderer bindings | |
ImGui_ImplGlfw_InitForOpenGL(window, true) | |
ImGui_ImplOpenGL3_Init(glsl_version) | |
return window, ctx | |
end | |
function renderloop(window, ctx, ui=()->nothing, hotloading=false) | |
try | |
while !GLFW.WindowShouldClose(window) | |
GLFW.PollEvents() | |
ImGui_ImplOpenGL3_NewFrame() | |
ImGui_ImplGlfw_NewFrame() | |
CImGui.NewFrame() | |
hotloading ? Base.invokelatest(ui) : ui() | |
CImGui.Render() | |
GLFW.MakeContextCurrent(window) | |
display_w, display_h = GLFW.GetFramebufferSize(window) | |
glViewport(0, 0, display_w, display_h) | |
glClearColor(0.2, 0.2, 0.2, 1) | |
glClear(GL_COLOR_BUFFER_BIT) | |
ImGui_ImplOpenGL3_RenderDrawData(CImGui.GetDrawData()) | |
GLFW.MakeContextCurrent(window) | |
GLFW.SwapBuffers(window) | |
yield() | |
end | |
catch e | |
@error "Error in renderloop!" exception=e | |
Base.show_backtrace(stderr, catch_backtrace()) | |
finally | |
ImGui_ImplOpenGL3_Shutdown() | |
ImGui_ImplGlfw_Shutdown() | |
CImGui.DestroyContext(ctx) | |
GLFW.DestroyWindow(window) | |
end | |
end | |
function render(ui; width=1280, height=720, title::AbstractString="Demo", hotloading=false) | |
window, ctx = init_renderer(width, height, title) | |
GC.@preserve window ctx begin | |
t = @async renderloop(window, ctx, ui, hotloading) | |
end | |
return t | |
end | |
end # module |
You can try Renderer from CImGui master branch: https://github.com/Gnimuc/CImGui.jl/blob/master/examples/Renderer.jl
Thanks for the suggestion. I tried the example Renderer. However, there is now a different error:
With the latest tagged version of CImGui (v1.79.0) I get:
ERROR: LoadError: InitError: UndefVarError: glfwWindowHint not defined
Then I tried to update to latest master (v1.82.0) (with add CImGui#master
) and there I get:
ERROR: LoadError: UndefVarError: GLFWBackend not defined
I figured, that I have to replace
using CImGui.GLFWBackend
using CImGui.OpenGLBackend
using CImGui.GLFWBackend.GLFW
using CImGui.OpenGLBackend.ModernGL
with
using CImGui.ImGuiGLFWBackend
using CImGui.ImGuiOpenGLBackend
using CImGui.ImGuiGLFWBackend.LibGLFW
using CImGui.ImGuiOpenGLBackend.ModernGL
But then I run into the next error:
ERROR: LoadError: UndefVarError: ImGui_ImplGlfw_InitForOpenGL not defined
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
If I run this app and click to open one of the
CollapsingHeader
, I will get the following error:EDIT: BTW I use Julia v1.7