diff --git a/imgui-binding/src/main/java/imgui/ImDrawList.java b/imgui-binding/src/main/java/imgui/ImDrawList.java index 4fad02e..1f69287 100644 --- a/imgui-binding/src/main/java/imgui/ImDrawList.java +++ b/imgui-binding/src/main/java/imgui/ImDrawList.java @@ -12,8 +12,6 @@ package imgui; * Important: Primitives are always added to the list and not culled (culling is done at higher-level by ImGui:: functions), if you use this API a lot consider coarse culling your drawn objects. */ public final class ImDrawList { - // BINDING NOTICE: - // For proper usage in getWindowDrawList(), getBackgroundDrawList(), getForegroundDrawList() we should be able to change object pointer. long ptr; ImDrawList(final long ptr) { diff --git a/imgui-binding/src/main/java/imgui/ImGui.java b/imgui-binding/src/main/java/imgui/ImGui.java index 92fd160..b6bdcc8 100644 --- a/imgui-binding/src/main/java/imgui/ImGui.java +++ b/imgui-binding/src/main/java/imgui/ImGui.java @@ -27,6 +27,7 @@ public final class ImGui { private static final ImDrawList WINDOW_DRAW_LIST; private static final ImDrawList BACKGROUND_DRAW_LIST; private static final ImDrawList FOREGROUND_DRAW_LIST; + private static final ImGuiStorage IMGUI_STORAGE; private static ImDrawData drawData; private static ImFont font; @@ -51,6 +52,7 @@ public final class ImGui { WINDOW_DRAW_LIST = new ImDrawList(0); BACKGROUND_DRAW_LIST = new ImDrawList(0); FOREGROUND_DRAW_LIST = new ImDrawList(0); + IMGUI_STORAGE = new ImGuiStorage(0); nInitJni(); ImDrawList.nInit(); @@ -61,6 +63,7 @@ public final class ImGui { ImFont.nInit(); ImGuiStyle.nInit(); ImGuiWindowClass.nInit(); + ImGuiStorage.nInit(); nInitInputTextData(); } @@ -4616,7 +4619,36 @@ public final class ImGui { return env->NewStringUTF(ImGui::GetStyleColorName(imGuiCol)); */ - // TODO SetStateStorage, GetStateStorage + /** + * Replace current window storage with our own (if you want to manipulate it yourself, typically clear subsection of it). + */ + public static void setStateStorage(final ImGuiStorage storage) { + nSetStateStorage(storage.ptr); + } + + private static native void nSetStateStorage(long imGuiStoragePtr); /* + ImGui::SetStateStorage((ImGuiStorage*)imGuiStoragePtr); + */ + + /** + * BINDING NOTICE: to minimize overhead, method ALWAYS returns the same object, but changes its underlying pointer. + * If you need to get an object with constant pointer (which will point to the same window all the time) use {@link #getStateStorageNew()}. + */ + public static ImGuiStorage getStateStorage() { + IMGUI_STORAGE.ptr = nGetStateStorage(); + return IMGUI_STORAGE; + } + + /** + * BINDING NOTICE: returns {@link ImGuiStorage} for current window with constant pointer to it. Prefer to use {@link #getStateStorage()}. + */ + public static ImGuiStorage getStateStorageNew() { + return new ImGuiStorage(nGetStateStorage()); + } + + private static native long nGetStateStorage(); /* + return (intptr_t)ImGui::GetStateStorage(); + */ /** * Calculate coarse clipping for large list of evenly sized items. Prefer using the ImGuiListClipper higher-level helper if you can. diff --git a/imgui-binding/src/main/java/imgui/ImGuiStorage.java b/imgui-binding/src/main/java/imgui/ImGuiStorage.java new file mode 100644 index 0000000..18b2cdf --- /dev/null +++ b/imgui-binding/src/main/java/imgui/ImGuiStorage.java @@ -0,0 +1,114 @@ +package imgui; + +/** + * Helper: Key-Value storage + * Typically you don't have to worry about this since a storage is held within each Window. + * We use it to e.g. store collapse state for a tree (Int 0/1) + * This is optimized for efficient lookup (dichotomy into a contiguous buffer) and rare insertion (typically tied to user interactions aka max once a frame) + * You can use it as custom user storage for temporary values. Declare your own storage if, for example: + * - You want to manipulate the open/close state of a particular sub-tree in your interface (tree node uses Int 0/1 to store their state). + * - You want to store custom debug data easily without adding or editing structures in your code (probably not efficient, but convenient) + * Types are NOT stored, so it is up to you to make sure your Key don't collide with different types. + */ +public final class ImGuiStorage implements ImGuiDestroyableStruct { + long ptr; + + /** + * This class will create a native structure. + * Call {@link #destroy()} method to manually free used memory. + */ + public ImGuiStorage() { + ImGui.touch(); + ptr = nCreate(); + } + + ImGuiStorage(final long ptr) { + this.ptr = ptr; + } + + @Override + public void destroy() { + nDestroy(ptr); + } + + /*JNI + #include + #include + + jfieldID imGuiStoragePtrID; + + #define IMGUI_STORAGE ((ImGuiStorage*)env->GetLongField(object, imGuiStoragePtrID)) + */ + + static native void nInit(); /* + jclass jImGuiStorageClass = env->FindClass("imgui/ImGuiStorage"); + imGuiStoragePtrID = env->GetFieldID(jImGuiStorageClass, "ptr", "J"); + */ + + private native long nCreate(); /* + ImGuiStorage* imGuiStorage = new ImGuiStorage(); + return (intptr_t)imGuiStorage; + */ + + private native void nDestroy(long ptr); /* + delete (ImGuiStorage*)ptr; + */ + + // - Get***() functions find pair, never add/allocate. Pairs are sorted so a query is O(log N) + // - Set***() functions find pair, insertion on demand if missing. + // - Sorted insertion is costly, paid once. A typical frame shouldn't need to insert any new pair. + + public native void clear(); /* + IMGUI_STORAGE->Clear(); + */ + + public native int getInt(int imGuiID); /* + return IMGUI_STORAGE->GetInt(imGuiID); + */ + + public native int getInt(int imGuiID, int defaultVal); /* + return IMGUI_STORAGE->GetInt(imGuiID, defaultVal); + */ + + public native void setInt(int imGuiID, int val); /* + IMGUI_STORAGE->SetInt(imGuiID, val); + */ + + public native boolean getBool(int imGuiID); /* + return IMGUI_STORAGE->GetBool(imGuiID); + */ + + public native boolean getBool(int imGuiID, boolean defaultVal); /* + return IMGUI_STORAGE->GetBool(imGuiID, defaultVal); + */ + + public native void setBool(int imGuiID, boolean val); /* + IMGUI_STORAGE->SetBool(imGuiID, val); + */ + + public native float getFloat(int imGuiID); /* + return IMGUI_STORAGE->GetFloat(imGuiID); + */ + + public native float getFloat(int imGuiID, float defaultVal); /* + return IMGUI_STORAGE->GetFloat(imGuiID, defaultVal); + */ + + public native void setFloat(int imGuiID, float val); /* + IMGUI_STORAGE->SetFloat(imGuiID, val); + */ + + /** + * Use on your own storage if you know only integer are being stored (open/close all tree nodes) + */ + public native void setAllInt(int val); /* + IMGUI_STORAGE->SetAllInt(val); + */ + + /** + * For quicker full rebuild of a storage (instead of an incremental one), you may add all your contents and then sort once. + */ + public native void buildSortByKey(); /* + IMGUI_STORAGE->BuildSortByKey(); + */ +}