#include "cell.h" #include "imgui.h" // Conditionally include ImPlot and ImNodes // #define ENABLE_IMPLOT // #define ENABLE_IMNODES #ifdef ENABLE_IMPLOT #include "implot.h" #endif #ifdef ENABLE_IMNODES #include "imnodes.h" #endif #include #include #include #include #include "imgui_impl_sdl3.h" #include "imgui_impl_sdlrenderer3.h" //#include "imgui_impl_sdlgpu3.h" #include "qjs_macros.h" // Forward declarations for the functions we need extern "C" { SDL_Window *js2SDL_Window(JSContext *js, JSValue v); SDL_Renderer *js2SDL_Renderer(JSContext *js, JSValue v); SDL_Texture *js2SDL_Texture(JSContext *js, JSValue v); double js2number(JSContext *js, JSValue v); } // ==================== UTILITY FUNCTIONS ==================== static inline ImVec2 js2imvec2(JSContext *js, JSValue v) { ImVec2 c; double dx, dy; JSValue x = JS_GetPropertyUint32(js, v, 0); JSValue y = JS_GetPropertyUint32(js, v, 1); JS_ToFloat64(js, &dx, x); JS_ToFloat64(js, &dy, y); JS_FreeValue(js, x); JS_FreeValue(js, y); c.x = dx; c.y = dy; return c; } static inline ImVec4 js2imvec4(JSContext *js, JSValue v) { ImVec4 c; double dx, dy, dz, dw; JSValue x = JS_GetPropertyUint32(js, v, 0); JSValue y = JS_GetPropertyUint32(js, v, 1); JSValue z = JS_GetPropertyUint32(js, v, 2); JSValue w = JS_GetPropertyUint32(js, v, 3); JS_ToFloat64(js, &dx, x); JS_ToFloat64(js, &dy, y); JS_ToFloat64(js, &dz, z); JS_ToFloat64(js, &dw, w); JS_FreeValue(js, x); JS_FreeValue(js, y); JS_FreeValue(js, z); JS_FreeValue(js, w); c.x = dx; c.y = dy; c.z = dz; c.w = dw; return c; } static inline JSValue imvec22js(JSContext *js, ImVec2 vec) { JSValue v = JS_NewObject(js); JS_SetPropertyUint32(js, v, 0, JS_NewFloat64(js, vec.x)); JS_SetPropertyUint32(js, v, 1, JS_NewFloat64(js, vec.y)); return v; } ImU32 js2imu32(JSContext *js, JSValue v) { return ImGui::ColorConvertFloat4ToU32(js2imvec4(js, v)); } // ==================== IMGUI CORE FUNCTIONS ==================== JSC_CCALL(imgui_window, const char *str = JS_ToCString(js,argv[0]); bool active = true; ImGui::Begin(str, &active); JS_Call(js, argv[1], JS_NULL, 0, NULL); ImGui::End(); JS_FreeCString(js,str); return JS_NewBool(js,active); ) JSC_SCALL(imgui_menu, if (ImGui::BeginMenu(str)) { JS_Call(js, argv[1], JS_NULL, 0, NULL); ImGui::EndMenu(); } ) JSC_CCALL(imgui_menubar, if (ImGui::BeginMenuBar()) { JS_Call(js, argv[0], JS_NULL, 0, NULL); ImGui::EndMenuBar(); } ) JSC_CCALL(imgui_mainmenubar, if (ImGui::BeginMainMenuBar()) { JS_Call(js, argv[0], JS_NULL, 0, NULL); ImGui::EndMainMenuBar(); } ) JSC_CCALL(imgui_menuitem, const char *name = JS_ToCString(js,argv[0]); const char *keyfn = JS_IsNull(argv[1]) ? NULL : JS_ToCString(js,argv[1]); bool on = JS_IsNull(argv[3]) ? false : JS_ToBool(js,argv[3]); if (ImGui::MenuItem(JS_ToBool(js,argv[0]) ? name : "##empty" ,keyfn, &on)) JS_Call(js, argv[2], JS_NULL, 0, NULL); if (!JS_IsNull(argv[0])) JS_FreeCString(js,name); if (keyfn) JS_FreeCString(js,keyfn); return JS_NewBool(js,on); ) JSC_SSCALL(imgui_textinput, char buffer[512]; if (JS_IsNull(argv[1])) buffer[0] = 0; else strncpy(buffer, str2, sizeof(buffer)-1); ImGui::InputText(str, buffer, sizeof(buffer)); if (strcmp(buffer, str2)) ret = JS_NewString(js,buffer); else ret = JS_DupValue(js,argv[1]); ) JSC_SSCALL(imgui_textbox, char buffer[512]; if (JS_IsNull(argv[1])) buffer[0] = 0; else strncpy(buffer, str2, sizeof(buffer)-1); ImGui::InputTextMultiline(str, buffer, sizeof(buffer)); if (strcmp(buffer, str2)) ret = JS_NewString(js,buffer); else ret = JS_DupValue(js,argv[1]); ) JSC_SCALL(imgui_text, ImGui::Text("%s", str) ) JSC_SCALL(imgui_button, if (ImGui::Button(str)) JS_Call(js, argv[1], JS_NULL, 0, NULL); ) JSC_SCALL(imgui_slider, float low = JS_IsNull(argv[2]) ? 0.0 : js2number(js, argv[2]); float high = JS_IsNull(argv[3]) ? 1.0 : js2number(js, argv[3]); if (JS_IsArray(js, argv[1])) { int n = JS_ArrayLength(js, argv[1]); float a[4]; // Max 4 elements for SliderFloat4 // Read values from JS array for (int i = 0; i < n && i < 4; i++) { JSValue val = JS_GetPropertyUint32(js, argv[1], i); double d; JS_ToFloat64(js, &d, val); a[i] = (float)d; JS_FreeValue(js, val); } switch(n) { case 2: ImGui::SliderFloat2(str, a, low, high); break; case 3: ImGui::SliderFloat3(str, a, low, high); break; case 4: ImGui::SliderFloat4(str, a, low, high); break; } // Write values back to JS array ret = JS_NewArray(js); for (int i = 0; i < n && i < 4; i++) { JS_SetPropertyUint32(js, ret, i, JS_NewFloat64(js, a[i])); } } else { float val = js2number(js, argv[1]); ImGui::SliderFloat(str, &val, low, high, "%.3f"); ret = JS_NewFloat64(js, val); } ) JSC_SCALL(imgui_intslider, int low = JS_IsNull(argv[2]) ? 0 : js2number(js, argv[2]); int high = JS_IsNull(argv[3]) ? 100 : js2number(js, argv[3]); if (JS_IsArray(js, argv[1])) { int n = JS_ArrayLength(js, argv[1]); int a[4]; // Max 4 elements for SliderInt4 // Read values from JS array for (int i = 0; i < n && i < 4; i++) { JSValue val = JS_GetPropertyUint32(js, argv[1], i); double d; JS_ToFloat64(js, &d, val); a[i] = (int)d; JS_FreeValue(js, val); } switch(n) { case 2: ImGui::SliderInt2(str, a, low, high); break; case 3: ImGui::SliderInt3(str, a, low, high); break; case 4: ImGui::SliderInt4(str, a, low, high); break; } // Write values back to JS array ret = JS_NewArray(js); for (int i = 0; i < n && i < 4; i++) { JS_SetPropertyUint32(js, ret, i, JS_NewInt32(js, a[i])); } } else { int val = js2number(js, argv[1]); ImGui::SliderInt(str, &val, low, high); ret = JS_NewInt32(js, val); } ) JSC_SCALL(imgui_checkbox, bool val = JS_ToBool(js, argv[1]); ImGui::Checkbox(str, &val); ret = JS_NewBool(js,val); ) JSC_CCALL(imgui_pushid, ImGui::PushID(js2number(js, argv[0])); ) JSC_CCALL(imgui_popid, ImGui::PopID(); ) JSC_CCALL(imgui_image, SDL_Texture *tex = js2SDL_Texture(js,argv[0]); ImGui::Image((ImTextureID)tex, ImVec2(100, 100), ImVec2(0,0), ImVec2(1,1)); ) JSC_SCALL(imgui_imagebutton, SDL_Texture *tex = js2SDL_Texture(js,argv[1]); if (ImGui::ImageButton(str, (ImTextureID)tex, ImVec2(100, 100))) JS_Call(js, argv[2], JS_NULL, 0, NULL); ) JSC_CCALL(imgui_sameline, ImGui::SameLine(js2number(js, argv[0])) ) JSC_CCALL(imgui_columns, ImGui::Columns(js2number(js, argv[0])) ) JSC_CCALL(imgui_nextcolumn, ImGui::NextColumn() ) JSC_SCALL(imgui_collapsingheader, ret = JS_NewBool(js,ImGui::CollapsingHeader(str)) ) JSC_SCALL(imgui_radio, ret = JS_NewBool(js,ImGui::RadioButton(str, JS_ToBool(js, argv[1])))) JSC_SCALL(imgui_tree, if (ImGui::TreeNode(str)) { JS_Call(js, argv[1],JS_NULL, 0,NULL); ImGui::TreePop(); } ) JSC_SCALL(imgui_tabbar, if (ImGui::BeginTabBar(str)) { JS_Call(js, argv[1],JS_NULL, 0,NULL); ImGui::EndTabBar(); } ) JSC_SCALL(imgui_tab, if (ImGui::BeginTabItem(str)) { JS_Call(js, argv[1],JS_NULL, 0,NULL); ImGui::EndTabItem(); } ) JSC_SCALL(imgui_listbox, /* char **arr = js2strarr(argv[1]); int n = JS_ArrayLength(js, argv[1]); int idx = js2number(js, argv[2]); ImGui::ListBox(str, &idx, arr, n, 4); for (int i = 0; i < n; i++) free(arr[i]); // arrfree(arr); // TODO: Doesn't this need freed? ret = JS_NewInt32(js,idx);*/ ) JSC_SCALL(imgui_int, int n = js2number(js, argv[1]); ImGui::InputInt(str, &n); ret = JS_NewInt32(js, n); ) JSC_SCALL(imgui_open_popup, ImGui::OpenPopup(str); ) JSC_SCALL(imgui_popup, if (ImGui::BeginPopup(str)) { JS_Call(js, argv[1],JS_NULL, 0,NULL); ImGui::EndPopup(); } ) JSC_CCALL(imgui_close_popup, ImGui::CloseCurrentPopup(); ) JSC_SCALL(imgui_modal, if (ImGui::BeginPopupModal(str)) { JS_Call(js, argv[1],JS_NULL, 0,NULL); ImGui::EndPopup(); } ) JSC_SCALL(imgui_context, if (ImGui::BeginPopupContextItem(str)) { JS_Call(js, argv[1],JS_NULL, 0,NULL); ImGui::EndPopup(); } ) JSC_SCALL(imgui_table, int flags = ImGuiTableFlags_Resizable | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_SizingStretchProp; bool sort = false; if (!JS_IsNull(argv[3])) sort = true; if (sort) flags |= ImGuiTableFlags_Sortable; if (ImGui::BeginTable(str, js2number(js, argv[1]), flags)) { JS_Call(js, argv[2], JS_NULL, 0, NULL); if (sort) { ImGuiTableSortSpecs* sort_specs = ImGui::TableGetSortSpecs(); if (sort_specs && sort_specs->SpecsDirty) { for (int i = 0; i < sort_specs->SpecsCount; i++) { const ImGuiTableColumnSortSpecs* spec = &sort_specs->Specs[i]; JSValue send[2]; send[0] = JS_NewInt32(js,spec->ColumnIndex); send[1] = JS_NewBool(js,spec->SortDirection == ImGuiSortDirection_Ascending); JS_Call(js, argv[3], JS_NULL, 2, send); JS_FreeValue(js, send[0]); JS_FreeValue(js, send[1]); } sort_specs->SpecsDirty = false; } } ImGui::EndTable(); } ) JSC_CCALL(imgui_tablenextrow, ImGui::TableNextRow()) JSC_CCALL(imgui_tablenextcolumn, ImGui::TableNextColumn()) JSC_SCALL(imgui_tablesetupcolumn, ImGui::TableSetupColumn(str)) JSC_CCALL(imgui_tableheadersrow, ImGui::TableHeadersRow()) JSC_CCALL(imgui_tableangledheadersrow, ImGui::TableAngledHeadersRow()) JSC_SCALL(imgui_dnd, if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) { double n = js2number(js, argv[1]); ImGui::SetDragDropPayload(str, &n, sizeof(n)); // JS_Call(js, argv[2], JS_NULL, 2, send); ImGui::EndDragDropSource(); } ) JSC_SCALL(imgui_dndtarget, if (ImGui::BeginDragDropTarget()) { if (const ImGuiPayload *payload = ImGui::AcceptDragDropPayload(str)) { JSValue n = JS_NewFloat64(js,*(double*)payload->Data); JS_Call(js, argv[1], JS_NULL, 1, &n); } ImGui::EndDragDropTarget(); } ) JSC_SCALL(imgui_color, /* int n = JS_ArrayLength(js, argv[1]); float color[n]; js2floatarr(argv[1],n,color); if (n == 3) ImGui::ColorEdit3(str, color); else if (n == 4) ImGui::ColorEdit4(str, color); ret = floatarr2js(n, color);*/ ) // Drawing functions JSC_CCALL(imgui_rectfilled, ImGui::GetWindowDrawList()->AddRectFilled(js2imvec2(js,argv[0]), js2imvec2(js,argv[1]), js2imu32(js,argv[2])); ) JSC_CCALL(imgui_line, ImGui::GetWindowDrawList()->AddLine(js2imvec2(js,argv[0]), js2imvec2(js,argv[1]),js2imu32(js, argv[2])); ) JSC_CCALL(imgui_point, ImGui::GetWindowDrawList()->AddCircleFilled(js2imvec2(js,argv[0]), js2number(js, argv[1]), js2imu32(js, argv[2])); ) JSC_CCALL(imgui_cursorscreenpos, ImVec2 v = ImGui::GetCursorScreenPos(); return imvec22js(js, v); ) JSC_CCALL(imgui_setcursorscreenpos, ImGui::SetCursorScreenPos(js2imvec2(js,argv[0])); ) JSC_CCALL(imgui_contentregionavail, return imvec22js(js, ImGui::GetContentRegionAvail()); ) JSC_CCALL(imgui_beziercubic, ImGui::GetWindowDrawList()->AddBezierCubic(js2imvec2(js,argv[0]), js2imvec2(js,argv[1]), js2imvec2(js,argv[2]), js2imvec2(js,argv[3]), js2imu32(js, argv[4]), js2number(js, argv[5])); ) JSC_CCALL(imgui_bezierquad, ImGui::GetWindowDrawList()->AddBezierQuadratic(js2imvec2(js,argv[0]), js2imvec2(js,argv[1]), js2imvec2(js,argv[2]), js2imu32(js, argv[3]), js2number(js, argv[4])); ) JSC_SCALL(imgui_drawtext, ImGui::GetWindowDrawList()->AddText(js2imvec2(js,argv[1]), js2imu32(js,argv[2]), str); ) JSC_CCALL(imgui_rect, ImGui::GetWindowDrawList()->AddRect(js2imvec2(js,argv[0]), js2imvec2(js,argv[1]), js2imu32(js,argv[2])); ) JSC_CCALL(imgui_mousehoveringrect, return JS_NewBool(js,ImGui::IsMouseHoveringRect(js2imvec2(js,argv[0]), js2imvec2(js,argv[1]))); ) JSC_CCALL(imgui_mouseclicked, return JS_NewBool(js,ImGui::IsMouseClicked(js2number(js, argv[0]))); ) JSC_CCALL(imgui_mousedown, return JS_NewBool(js,ImGui::IsMouseDown(js2number(js, argv[0]))); ) JSC_CCALL(imgui_mousereleased, return JS_NewBool(js,ImGui::IsMouseReleased(js2number(js, argv[0]))); ) JSC_CCALL(imgui_mousedragging, return JS_NewBool(js,ImGui::IsMouseDragging(js2number(js, argv[0]))); ) JSC_CCALL(imgui_mousedelta, ImVec2 dm = ImGui::GetIO().MouseDelta; return imvec22js(js, (ImVec2){dm.x,dm.y}); ) JSC_CCALL(imgui_dummy, ImGui::Dummy(js2imvec2(js,argv[0])); ) JSC_SCALL(imgui_invisiblebutton, ImGui::InvisibleButton(str, js2imvec2(js,argv[1])); ) JSC_CCALL(imgui_width, ImGui::PushItemWidth(js2number(js, argv[0])); ) JSC_CCALL(imgui_windowpos, return imvec22js(js,ImGui::GetWindowPos()); ) JSC_SCALL(imgui_setclipboard, ImGui::SetClipboardText(str); ) // Global variable to store logical presentation state static int stored_logical_w = 0; static int stored_logical_h = 0; static SDL_RendererLogicalPresentation stored_logical_mode = SDL_LOGICAL_PRESENTATION_DISABLED; static SDL_ScaleMode stored_scale_mode = SDL_SCALEMODE_NEAREST; JSC_CCALL(imgui_newframe, ImGui_ImplSDL3_NewFrame(); ImGui::NewFrame(); ) JSC_CCALL(imgui_endframe, ImGui::Render(); SDL_Renderer *renderer = js2SDL_Renderer(js,argv[0]); int w, h; SDL_RendererLogicalPresentation mode; SDL_GetRenderLogicalPresentation(renderer, &w, &h, &mode); SDL_SetRenderLogicalPresentation(renderer,0,0,SDL_LOGICAL_PRESENTATION_DISABLED); ImGui_ImplSDLRenderer3_RenderDrawData(ImGui::GetDrawData(), renderer); SDL_SetRenderLogicalPresentation(renderer,w,h,mode); ) JSC_CCALL(imgui_wantmouse, return JS_NewBool(js, ImGui::GetIO().WantCaptureMouse); ) JSC_CCALL(imgui_wantkeys, return JS_NewBool(js, ImGui::GetIO().WantCaptureKeyboard); ) JSC_CCALL(imgui_init, ImGui::CreateContext(); ImGuiIO& io = ImGui::GetIO(); io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; ImGui::StyleColorsDark(); SDL_Window *window = js2SDL_Window(js,argv[0]); SDL_Renderer *renderer = js2SDL_Renderer(js,argv[1]); ImGui_ImplSDL3_InitForSDLRenderer(window, renderer); ImGui_ImplSDLRenderer3_Init(renderer); io.IniFilename = ".prosperon/imgui.ini"; ImGui::LoadIniSettingsFromDisk(".prosperon/imgui.ini"); #ifdef ENABLE_IMPLOT ImPlot::CreateContext(); #endif #ifdef ENABLE_IMNODES ImNodes::CreateContext(); #endif ) // ==================== IMPLOT FUNCTIONS ==================== #ifdef ENABLE_IMPLOT int num_to_yaxis(int y) { switch(y) { case 0: return ImAxis_Y1; case 1: return ImAxis_Y2; case 2: return ImAxis_Y3; } return ImAxis_Y1; } int num_to_xaxis(int x) { switch(x) { case 0: return ImAxis_X1; case 1: return ImAxis_X2; case 2: return ImAxis_X3; } return ImAxis_X1; } ImPlotPoint js2plotvec2(JSContext *js, JSValue v) { ImVec2 c = js2imvec2(js, v); return ImPlotPoint(c); } JSValue plotimvec22js(JSContext *js, ImPlotPoint v) { return imvec22js(js, ImVec2{v.x,v.y}); } static ImVec2 *plotdata = NULL; void fill_plotdata(JSContext *js, JSValue v, JSValue last) { arrsetlen(plotdata, 0); if (JS_IsArray(js,js_getpropidx(v, 0))) { for (int i = 0; i < JS_ArrayLength(js, v); i++) arrput(plotdata, js2imvec2(js, js_getpropidx(v, i))); } else { // Fill it with the x axis being the array index for (int i = 0; i < JS_ArrayLength(js, v); i++) { if (JS_IsNull(js_getpropidx(v,i))) continue; ImVec2 c; c.x = i; c.y = js2number(js, js_getpropidx(v,i)); arrput(plotdata, c); } } if (!JS_IsNull(last)) { int frame = js2number(js, last); ImVec2 c = js2imvec2(js,last); c.y = arrlast(plotdata).y; arrput(plotdata, c); } } JSC_SCALL(imgui_plot, if (ImPlot::BeginPlot(str)) { JS_Call(js, argv[1], JS_NULL, 0, NULL); ImPlot::EndPlot(); } ) #define PLOT_FN(NAME, FN, ADD, SHADED) JSC_SCALL(imgui_##NAME, \ fill_plotdata(js, argv[1], argv[3]); \ bool shaded = JS_ToBool(js,argv[2]);\ int flag = 0; \ if (shaded) flag = SHADED; \ ImPlot::FN(str, &plotdata[0].x, &plotdata[0].y, arrlen(plotdata), ADD flag, 0, sizeof(ImVec2)); \ ) \ PLOT_FN(lineplot, PlotLine,,ImPlotLineFlags_Shaded) PLOT_FN(scatterplot, PlotScatter,,0) PLOT_FN(stairplot, PlotStairs,,ImPlotStairsFlags_Shaded) PLOT_FN(digitalplot, PlotDigital,,0) JSC_SCALL(imgui_barplot, fill_plotdata(js, argv[1], JS_NULL); ImPlot::PlotBars(str, &plotdata[0].x, &plotdata[0].y, JS_ArrayLength(js, argv[1]), js2number(js, argv[2]), 0, 0, sizeof(ImVec2)); ) JSC_SCALL(imgui_histogramplot, size_t offset, len, per_e; JSValue typed = JS_GetTypedArrayBuffer(js, argv[1], &offset, &len, &per_e); ImPlot::PlotHistogram(str, js_get_blob_data(js, NULL, typed), JS_ArrayLength(js, argv[1])); JS_FreeValue(js, typed); ) JSC_SCALL(imgui_textplot, ImVec2 c = js2imvec2(js, argv[1]); ImPlot::PlotText(str, c.x, c.y); ) JSC_CCALL(imgui_inplot, ImVec2 v = js2imvec2(js, argv[0]); ImPlotRect lm = ImPlot::GetPlotLimits(); if (v.x > lm.X.Min && v.x < lm.X.Max && v.y > lm.Y.Min && v.y < lm.Y.Max) return JS_NewBool(js,true); return JS_NewBool(js,false); ) JSC_CCALL(imgui_plothovered, return JS_NewBool(js,ImPlot::IsPlotHovered()); ) JSC_SSCALL(imgui_plotaxes, ImPlot::SetupAxes(str,str2); ) JSC_CCALL(imgui_plotmousepos, ImPlotPoint p = ImPlot::GetPlotMousePos(); return imvec22js(js, ImVec2{p.x,p.y}); ) JSC_CCALL(imgui_axeslimits, ImPlot::SetupAxesLimits(js2number(js, argv[0]), js2number(js, argv[1]), js2number(js, argv[2]), js2number(js, argv[3])); ) JSC_CCALL(imgui_fitaxis, ImPlot::SetNextAxisToFit((js2number(js, argv[0]) == 0) ? ImAxis_X1 : ImAxis_Y1); ) JSC_CCALL(imgui_plotpos, return plotimvec22js(js, ImPlot::GetPlotPos()); ) JSC_CCALL(imgui_plot2pixels, return imvec22js(js, ImPlot::PlotToPixels(js2plotvec2(js, argv[0]))); ) JSC_CCALL(imgui_plotlimits, ImPlotRect lim = ImPlot::GetPlotLimits(); JSValue xlim = JS_NewObject(js); JS_SetPropertyStr(js,xlim, "min", JS_NewFloat64(js,lim.X.Min)); JS_SetPropertyStr(js,xlim, "max", JS_NewFloat64(js,lim.X.Max)); JSValue ylim = JS_NewObject(js); JS_SetPropertyStr(js,ylim, "min", JS_NewFloat64(js,lim.Y.Min)); JS_SetPropertyStr(js,ylim, "max", JS_NewFloat64(js,lim.Y.Max)); JSValue limits = JS_NewObject(js); JS_SetPropertyStr(js,limits, "x", xlim); JS_SetPropertyStr(js,limits, "y", ylim); return limits; ) static JSValue axis_fmts[10]; void jsformatter(double value, char *buff, int size, JSValue *fmt) { /* JSValue v = JS_NewFloat64(js,value); const char *str = JS_ToCString(js, JS_Call(js,*fmt, JS_NULL, 1, &v)); strncpy(buff,str, size); JS_FreeCString(js, str);*/ } JSC_CCALL(imgui_axisfmt, int y = num_to_yaxis(js2number(js, argv[0])); if (!JS_IsNull(axis_fmts[y])) { JS_FreeValue(js, axis_fmts[y]); axis_fmts[y] = JS_NULL; } axis_fmts[y] = JS_DupValue(js,argv[1]); ImPlot::SetupAxisFormat(y, (ImPlotFormatter)jsformatter, (void*)(axis_fmts+y)); ) JSC_CCALL(imgui_setaxes, int x = num_to_xaxis(js2number(js, argv[0])); int y = num_to_yaxis(js2number(js, argv[1])); ImPlot::SetAxes(x,y); ) JSC_CCALL(imgui_setupaxis, ImPlot::SetupAxis(num_to_yaxis(js2number(js, argv[0]))); ) #endif // ENABLE_IMPLOT // ==================== IMNODES FUNCTIONS ==================== #ifdef ENABLE_IMNODES JSC_CCALL(imgui_startnode, ImNodes::BeginNodeEditor(); JS_Call(js, argv[0], JS_NULL, 0,NULL); ImNodes::EndNodeEditor(); int start_attr; int end_attr; if (ImNodes::IsLinkCreated(&start_attr, &end_attr)) { JSValue ab[2]; ab[0] = JS_NewInt32(js,start_attr); ab[1] = JS_NewInt32(js,end_attr); JS_Call(js,argv[1], JS_NULL, 2, ab); for (int i = 0; i < 2; i++) JS_FreeValue(js, ab[i]); } int node_id; if (ImNodes::IsNodeHovered(&node_id)) { JSValue a = JS_NewInt32(js,node_id); JS_Call(js, argv[2], JS_NULL, 1,&a); JS_FreeValue(js,a); } int link_id; if (ImNodes::IsLinkHovered(&link_id)) { JSValue a = JS_NewInt32(js,link_id); JS_Call(js, argv[3], JS_NULL, 1,&a); JS_FreeValue(js,a); } ) JSC_CCALL(imgui_node, ImNodes::BeginNode(js2number(js, argv[0])); JS_Call(js, argv[1], JS_NULL, 0,NULL); ImNodes::EndNode(); ) JSC_CCALL(imgui_nodein, ImNodes::BeginInputAttribute(js2number(js, argv[0])); JS_Call(js, argv[1], JS_NULL, 0,NULL); ImNodes::EndInputAttribute(); ) JSC_CCALL(imgui_nodeout, ImNodes::BeginOutputAttribute(js2number(js, argv[0])); JS_Call(js, argv[1], JS_NULL, 0,NULL); ImNodes::EndOutputAttribute(); ) JSC_CCALL(imgui_nodelink, ImNodes::Link(js2number(js, argv[0]), js2number(js, argv[1]), js2number(js, argv[2])); ) JSC_CCALL(imgui_nodemini, ImNodes::MiniMap(js2number(js, argv[0]))) #endif // ENABLE_IMNODES // ==================== FUNCTION LISTS ==================== extern "C" { // Core ImGui functions const JSCFunctionListEntry js_imgui_funcs[] = { // Window functions MIST_FUNC_DEF(imgui, window, 2), MIST_FUNC_DEF(imgui, windowpos, 0), // Menu functions MIST_FUNC_DEF(imgui, menu, 2), MIST_FUNC_DEF(imgui, menubar, 1), MIST_FUNC_DEF(imgui, mainmenubar, 1), MIST_FUNC_DEF(imgui, menuitem, 3), // Input functions MIST_FUNC_DEF(imgui, textinput, 2), MIST_FUNC_DEF(imgui, textbox, 2), MIST_FUNC_DEF(imgui, int, 2), MIST_FUNC_DEF(imgui, slider, 4), MIST_FUNC_DEF(imgui, intslider, 4), MIST_FUNC_DEF(imgui, checkbox, 2), // Basic widgets MIST_FUNC_DEF(imgui, text, 1), MIST_FUNC_DEF(imgui, button, 2), MIST_FUNC_DEF(imgui, radio, 2), MIST_FUNC_DEF(imgui, image, 1), MIST_FUNC_DEF(imgui, imagebutton, 2), // Layout MIST_FUNC_DEF(imgui, sameline, 1), MIST_FUNC_DEF(imgui, columns, 1), MIST_FUNC_DEF(imgui, nextcolumn, 0), MIST_FUNC_DEF(imgui, dummy, 1), MIST_FUNC_DEF(imgui, invisiblebutton, 2), MIST_FUNC_DEF(imgui, width, 1), // Containers MIST_FUNC_DEF(imgui, collapsingheader, 1), MIST_FUNC_DEF(imgui, tree, 2), MIST_FUNC_DEF(imgui, tabbar, 2), MIST_FUNC_DEF(imgui, tab, 2), // Tables MIST_FUNC_DEF(imgui, table, 4), MIST_FUNC_DEF(imgui, tablenextcolumn,0), MIST_FUNC_DEF(imgui, tablenextrow,0), MIST_FUNC_DEF(imgui, tableheadersrow, 0), MIST_FUNC_DEF(imgui, tableangledheadersrow, 0), MIST_FUNC_DEF(imgui, tablesetupcolumn, 1), // ID stack MIST_FUNC_DEF(imgui, pushid, 1), MIST_FUNC_DEF(imgui, popid, 0), // Popups MIST_FUNC_DEF(imgui, open_popup, 1), MIST_FUNC_DEF(imgui, popup, 2), MIST_FUNC_DEF(imgui, close_popup,0), MIST_FUNC_DEF(imgui, modal, 2), MIST_FUNC_DEF(imgui, context,2), // Drag and drop MIST_FUNC_DEF(imgui, dnd, 3), MIST_FUNC_DEF(imgui, dndtarget, 2), // List box and color (currently stubbed) MIST_FUNC_DEF(imgui, listbox, 3), MIST_FUNC_DEF(imgui, color, 2), // Drawing functions MIST_FUNC_DEF(imgui, rect, 3), MIST_FUNC_DEF(imgui, rectfilled, 3), MIST_FUNC_DEF(imgui, line, 3), MIST_FUNC_DEF(imgui, bezierquad, 5), MIST_FUNC_DEF(imgui, beziercubic, 6), MIST_FUNC_DEF(imgui, point, 3), MIST_FUNC_DEF(imgui, drawtext, 3), // Position/region MIST_FUNC_DEF(imgui, cursorscreenpos, 0), MIST_FUNC_DEF(imgui, setcursorscreenpos, 1), MIST_FUNC_DEF(imgui, contentregionavail, 0), // Mouse functions MIST_FUNC_DEF(imgui, mousehoveringrect, 2), MIST_FUNC_DEF(imgui, mouseclicked, 1), MIST_FUNC_DEF(imgui, mousedown, 1), MIST_FUNC_DEF(imgui, mousereleased, 1), MIST_FUNC_DEF(imgui, mousedragging, 1), MIST_FUNC_DEF(imgui, mousedelta, 0), // System MIST_FUNC_DEF(imgui, setclipboard, 1), MIST_FUNC_DEF(imgui, wantmouse, 0), MIST_FUNC_DEF(imgui, wantkeys, 0), // Frame control MIST_FUNC_DEF(imgui, init, 2), MIST_FUNC_DEF(imgui, newframe, 0), MIST_FUNC_DEF(imgui, endframe, 1), }; #ifdef ENABLE_IMPLOT // ImPlot functions const JSCFunctionListEntry js_implot_funcs[] = { MIST_FUNC_DEF(imgui, plot, 2), MIST_FUNC_DEF(imgui, plot2pixels, 1), MIST_FUNC_DEF(imgui, plotpos, 0), MIST_FUNC_DEF(imgui, plotlimits, 0), MIST_FUNC_DEF(imgui, setaxes, 2), MIST_FUNC_DEF(imgui, setupaxis, 1), MIST_FUNC_DEF(imgui, axisfmt, 2), MIST_FUNC_DEF(imgui, inplot, 1), MIST_FUNC_DEF(imgui, lineplot, 4), MIST_FUNC_DEF(imgui, scatterplot, 4), MIST_FUNC_DEF(imgui, stairplot, 4), MIST_FUNC_DEF(imgui, digitalplot, 4), MIST_FUNC_DEF(imgui, barplot, 3), MIST_FUNC_DEF(imgui, textplot, 2), MIST_FUNC_DEF(imgui, histogramplot, 2), MIST_FUNC_DEF(imgui, plotaxes, 2), MIST_FUNC_DEF(imgui, plotmousepos, 0), MIST_FUNC_DEF(imgui, plothovered, 0), MIST_FUNC_DEF(imgui, axeslimits, 4), MIST_FUNC_DEF(imgui, fitaxis, 1), }; #endif #ifdef ENABLE_IMNODES // ImNodes functions const JSCFunctionListEntry js_imnodes_funcs[] = { MIST_FUNC_DEF(imgui, startnode, 4), MIST_FUNC_DEF(imgui, node, 2), MIST_FUNC_DEF(imgui, nodein, 2), MIST_FUNC_DEF(imgui, nodeout, 2), MIST_FUNC_DEF(imgui, nodelink, 3), MIST_FUNC_DEF(imgui, nodemini, 1), }; #endif void gui_input(SDL_Event *e) { ImGui_ImplSDL3_ProcessEvent(e); } JSValue js_imgui_use(JSContext *js) { JSValue imgui = JS_NewObject(js); // Add core ImGui functions JS_SetPropertyFunctionList(js, imgui, js_imgui_funcs, sizeof(js_imgui_funcs)/sizeof(js_imgui_funcs[0])); #ifdef ENABLE_IMPLOT // Add ImPlot functions under imgui.plot JSValue plot = JS_NewObject(js); JS_SetPropertyFunctionList(js, plot, js_implot_funcs, sizeof(js_implot_funcs)/sizeof(js_implot_funcs[0])); JS_SetPropertyStr(js, imgui, "plot", plot); #endif #ifdef ENABLE_IMNODES // Add ImNodes functions under imgui.node JSValue node = JS_NewObject(js); JS_SetPropertyFunctionList(js, node, js_imnodes_funcs, sizeof(js_imnodes_funcs)/sizeof(js_imnodes_funcs[0])); JS_SetPropertyStr(js, imgui, "node", node); #endif return imgui; } } // extern "C"