From 986aa532ff8dd4523c3a84751b156ea86066f9b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A2=A8=E6=81=92?= <57742561+moheng233@users.noreply.github.com> Date: Tue, 7 Feb 2023 19:13:02 +0800 Subject: [PATCH] [API] Added callback binding for InputText (#156) * Added callback binding for InputText * Add JavaDoc * Change * Add Javadoc * Fix Import * Teaks and improvements - Extended example; - Added input text callback ImGuiInputTextFlags#CallbackEdit; - Minor code improvements. --------- Co-authored-by: SpaiR --- .../main/java/ExampleInputTextCallback.java | 44 +++++ example/src/main/java/Extra.java | 6 + imgui-binding/src/main/java/imgui/ImGui.java | 49 ++++- .../imgui/ImGuiInputTextCallbackData.java | 182 ++++++++++++++++++ .../callback/ImGuiInputTextCallback.java | 17 ++ .../java/imgui/flag/ImGuiInputTextFlags.java | 4 + 6 files changed, 296 insertions(+), 6 deletions(-) create mode 100644 example/src/main/java/ExampleInputTextCallback.java create mode 100644 imgui-binding/src/main/java/imgui/ImGuiInputTextCallbackData.java create mode 100644 imgui-binding/src/main/java/imgui/callback/ImGuiInputTextCallback.java diff --git a/example/src/main/java/ExampleInputTextCallback.java b/example/src/main/java/ExampleInputTextCallback.java new file mode 100644 index 0000000..de6b23d --- /dev/null +++ b/example/src/main/java/ExampleInputTextCallback.java @@ -0,0 +1,44 @@ +import imgui.ImGui; +import imgui.ImGuiInputTextCallbackData; +import imgui.callback.ImGuiInputTextCallback; +import imgui.flag.ImGuiCond; +import imgui.flag.ImGuiInputTextFlags; +import imgui.type.ImBoolean; +import imgui.type.ImString; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +public class ExampleInputTextCallback { + private static final ImString STR = new ImString(); + private static final StringBuilder OUTPUT = new StringBuilder(); + private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss"); + + private static final ImGuiInputTextCallback CALLBACK = new ImGuiInputTextCallback() { + @Override + public void accept(final ImGuiInputTextCallbackData data) { + final char c = (char) data.getEventChar(); + if (c == 'h' || c == 'H') { + data.setEventChar('!'); + OUTPUT.append(DATE_FORMAT.format(LocalDateTime.now())).append(" :: Replaced!\n"); + } else if (c == 'w' || c == 'W') { + data.setEventChar(0); + OUTPUT.append(DATE_FORMAT.format(LocalDateTime.now())).append(" :: Discarded!\n"); + } else { + OUTPUT.append(DATE_FORMAT.format(LocalDateTime.now())).append(" :: Typed: ").append(c).append('\n'); + } + } + }; + + public static void show(final ImBoolean showInputTextCallback) { + ImGui.setNextWindowSize(400, 300, ImGuiCond.Once); + if (ImGui.begin("Input Text Callback Demo", showInputTextCallback)) { + ImGui.alignTextToFramePadding(); + ImGui.text("Try to input \"Hello World!\":"); + ImGui.sameLine(); + ImGui.inputText("##input", STR, ImGuiInputTextFlags.CallbackCharFilter, CALLBACK); + ImGui.text(OUTPUT.toString()); + } + ImGui.end(); + } +} diff --git a/example/src/main/java/Extra.java b/example/src/main/java/Extra.java index bc9ce4c..6f1d599 100644 --- a/example/src/main/java/Extra.java +++ b/example/src/main/java/Extra.java @@ -13,6 +13,7 @@ public class Extra { private static final ImBoolean SHOW_IMGUI_FILE_DIALOG_WINDOW = new ImBoolean(false); private static final ImBoolean SHOW_IMGUI_MEMORY_EDITOR_WINDOW = new ImBoolean(false); private static final ImBoolean SHOW_IMGUI_CANVAS_EDITOR_WINDOW = new ImBoolean(false); + private static final ImBoolean SHOW_IMGUI_INPUT_CALLBACK_WINDOW = new ImBoolean(false); private static final Graph GRAPH = new Graph(); @@ -28,6 +29,7 @@ public class Extra { ImGui.checkbox("Show ImGuiFileDialog Demo Window", SHOW_IMGUI_FILE_DIALOG_WINDOW); ImGui.checkbox("Show ImGui MemoryEditor Demo Window", SHOW_IMGUI_MEMORY_EDITOR_WINDOW); ImGui.checkbox("Show ImGui Canvas Demo Window", SHOW_IMGUI_CANVAS_EDITOR_WINDOW); + ImGui.checkbox("Show Imgui InputText Callback Window", SHOW_IMGUI_INPUT_CALLBACK_WINDOW); if (SHOW_DEMO_WINDOW.get()) { ImGui.showDemoWindow(SHOW_DEMO_WINDOW); @@ -68,5 +70,9 @@ public class Extra { if (SHOW_IMGUI_CANVAS_EDITOR_WINDOW.get()) { ExampleCanvasEditor.show(SHOW_IMGUI_CANVAS_EDITOR_WINDOW); } + + if (SHOW_IMGUI_INPUT_CALLBACK_WINDOW.get()) { + ExampleInputTextCallback.show(SHOW_IMGUI_INPUT_CALLBACK_WINDOW); + } } } diff --git a/imgui-binding/src/main/java/imgui/ImGui.java b/imgui-binding/src/main/java/imgui/ImGui.java index 05dacda..3994780 100644 --- a/imgui-binding/src/main/java/imgui/ImGui.java +++ b/imgui-binding/src/main/java/imgui/ImGui.java @@ -1,6 +1,7 @@ package imgui; import imgui.assertion.ImAssertCallback; +import imgui.callback.ImGuiInputTextCallback; import imgui.flag.ImGuiCond; import imgui.flag.ImGuiDragDropFlags; import imgui.flag.ImGuiInputTextFlags; @@ -2988,11 +2989,13 @@ public class ImGui { /*JNI jmethodID jImStringResizeInternalMID; + jmethodID jInputTextCallbackMID; jfieldID inputDataSizeID; jfieldID inputDataIsDirtyID; jfieldID inputDataIsResizedID; + struct InputTextCallbackUserData { JNIEnv* env; jobject* imString; @@ -3001,6 +3004,7 @@ public class ImGui { char* resizedBuf; jobject* textInputData; char* allowedChars; + jobject* handler; }; static int TextEditCallbackStub(ImGuiInputTextCallbackData* data) { @@ -3033,6 +3037,11 @@ public class ImGui { } } + if (userData->handler != NULL) { + JNIEnv* env = userData->env; + env->CallObjectMethod(*userData->handler, jInputTextCallbackMID, data); + } + return 0; } */ @@ -3045,41 +3054,68 @@ public class ImGui { jclass jImString = env->FindClass("imgui/type/ImString"); jImStringResizeInternalMID = env->GetMethodID(jImString, "resizeInternal", "(I)[B"); + + jclass jCallback = env->FindClass("imgui/callback/ImGuiInputTextCallback"); + jInputTextCallbackMID = env->GetMethodID(jCallback, "accept", "(J)V"); */ public static boolean inputText(String label, ImString text) { - return preInputText(false, label, null, text, 0, 0, ImGuiInputTextFlags.None); + return preInputText(false, label, null, text); } public static boolean inputText(String label, ImString text, int imGuiInputTextFlags) { return preInputText(false, label, null, text, 0, 0, imGuiInputTextFlags); } + public static boolean inputText(String label, ImString text, int imGuiInputTextFlags, ImGuiInputTextCallback callback) { + return preInputText(false, label, null, text, 0, 0, imGuiInputTextFlags, callback); + } + public static boolean inputTextMultiline(String label, ImString text) { - return preInputText(true, label, null, text, 0, 0, ImGuiInputTextFlags.None); + return preInputText(true, label, null, text); } public static boolean inputTextMultiline(String label, ImString text, float width, float height) { - return preInputText(true, label, null, text, width, height, ImGuiInputTextFlags.None); + return preInputText(true, label, null, text, width, height); } public static boolean inputTextMultiline(String label, ImString text, int imGuiInputTextFlags) { return preInputText(true, label, null, text, 0, 0, imGuiInputTextFlags); } + public static boolean inputTextMultiline(String label, ImString text, int imGuiInputTextFlags, ImGuiInputTextCallback callback) { + return preInputText(true, label, null, text, 0, 0, imGuiInputTextFlags, callback); + } + public static boolean inputTextMultiline(String label, ImString text, float width, float height, int imGuiInputTextFlags) { return preInputText(true, label, null, text, width, height, imGuiInputTextFlags); } + public static boolean inputTextMultiline(String label, ImString text, float width, float height, int imGuiInputTextFlags, ImGuiInputTextCallback callback) { + return preInputText(true, label, null, text, width, height, imGuiInputTextFlags, callback); + } + public static boolean inputTextWithHint(String label, String hint, ImString text) { - return preInputText(false, label, hint, text, 0, 0, ImGuiInputTextFlags.None); + return preInputText(false, label, hint, text); } public static boolean inputTextWithHint(String label, String hint, ImString text, int imGuiInputTextFlags) { return preInputText(false, label, hint, text, 0, 0, imGuiInputTextFlags); } + private static boolean preInputText(boolean multiline, String label, String hint, ImString text) { + return preInputText(multiline, label, hint, text, 0, 0); + } + + private static boolean preInputText(boolean multiline, String label, String hint, ImString text, float width, float height) { + return preInputText(multiline, label, hint, text, width, height, ImGuiInputTextFlags.None); + } + private static boolean preInputText(boolean multiline, String label, String hint, ImString text, float width, float height, int flags) { + return preInputText(multiline, label, hint, text, width, height, flags, null); + } + + private static boolean preInputText(boolean multiline, String label, String hint, ImString text, float width, float height, int flags, ImGuiInputTextCallback callback) { final ImString.InputData inputData = text.inputData; if (inputData.isResizable) { @@ -3095,10 +3131,10 @@ public class ImGui { hintLabel = ""; } - return nInputText(multiline, hint != null, label, hintLabel, text, text.getData(), text.getData().length, width, height, flags, inputData, inputData.allowedChars); + return nInputText(multiline, hint != null, label, hintLabel, text, text.getData(), text.getData().length, width, height, flags, inputData, inputData.allowedChars, callback); } - private static native boolean nInputText(boolean multiline, boolean hint, String label, String hintLabel, ImString imString, byte[] buf, int maxSize, float width, float height, int flags, ImString.InputData textInputData, String allowedChars); /* + private static native boolean nInputText(boolean multiline, boolean hint, String label, String hintLabel, ImString imString, byte[] buf, int maxSize, float width, float height, int flags, ImString.InputData textInputData, String allowedChars, ImGuiInputTextCallback callback); /* InputTextCallbackUserData userData; userData.imString = &imString; userData.maxSize = maxSize; @@ -3107,6 +3143,7 @@ public class ImGui { userData.textInputData = &textInputData; userData.env = env; userData.allowedChars = allowedChars; + userData.handler = &callback; bool valueChanged; diff --git a/imgui-binding/src/main/java/imgui/ImGuiInputTextCallbackData.java b/imgui-binding/src/main/java/imgui/ImGuiInputTextCallbackData.java new file mode 100644 index 0000000..c5943eb --- /dev/null +++ b/imgui-binding/src/main/java/imgui/ImGuiInputTextCallbackData.java @@ -0,0 +1,182 @@ +package imgui; + +import imgui.binding.ImGuiStruct; + +/** + * Shared state of InputText(), passed as an argument to your callback when a ImGuiInputTextFlags_Callback* flag is used.

+ * The callback function should return 0 by default.

+ * Callbacks (follow a flag name and see comments in ImGuiInputTextFlags_ declarations for more details)

+ * - ImGuiInputTextFlags_CallbackEdit: Callback on buffer edit (note that InputText() already returns true on edit, the callback is useful mainly to manipulate the underlying buffer while focus is active)

+ * - ImGuiInputTextFlags_CallbackAlways: Callback on each iteration

+ * - ImGuiInputTextFlags_CallbackCompletion: Callback on pressing TAB

+ * - ImGuiInputTextFlags_CallbackHistory: Callback on pressing Up/Down arrows

+ * - ImGuiInputTextFlags_CallbackCharFilter: Callback on character inputs to replace or discard them. Modify 'EventChar' to replace or discard, or return 1 in callback to discard.

+ * - ImGuiInputTextFlags_CallbackResize: Callback on buffer capacity changes request (beyond 'buf_size' parameter value), allowing the string to grow.

+ */ +public class ImGuiInputTextCallbackData extends ImGuiStruct { + public ImGuiInputTextCallbackData(final long ptr) { + super(ptr); + } + + /*JNI + #include "_common.h" + + #define IMGUI_CALLBACK_DATA ((ImGuiInputTextCallbackData*)STRUCT_PTR) + */ + + /** + * One ImGuiInputTextFlags_Callback* + * + * @return ImGuiInputTextFlags + */ + public native int getEventFlag(); /* + return IMGUI_CALLBACK_DATA->EventFlag; + */ + + /** + * What user passed to InputText() + * + * @return ImGuiInputTextFlags + */ + public native int getFlags(); /* + return IMGUI_CALLBACK_DATA->Flags; + */ + + /** + * [CharFilter] Character input; + * + * @return Character input + */ + public native int getEventChar(); /* + return IMGUI_CALLBACK_DATA->EventChar; + */ + + /** + * [CharFilter] Replace character with another one, or set to zero to drop. return 1 is equivalent to setting EventChar=0; + * + * @param c Replaced characters + */ + public void setEventChar(final char c) { + setEventChar((int) c); + } + + /** + * [CharFilter] Replace character with another one, or set to zero to drop. return 1 is equivalent to setting EventChar=0; + * + * @param c Replaced characters + */ + public native void setEventChar(int c); /* + IMGUI_CALLBACK_DATA->EventChar = c; + */ + + /** + * [Completion,History] + * + * @return Key pressed (Up/Down/TAB) + */ + public native int getEventKey(); /* + return IMGUI_CALLBACK_DATA->EventKey; + */ + + /** + * [Resize] Can replace pointer

+ * [Completion,History,Always] Only write to pointed data, don't replace the actual pointer! + * + * @return Buf + */ + public native String getBuf(); /* + return env->NewStringUTF(IMGUI_CALLBACK_DATA->Buf); + */ + + /** + * Set if you modify Buf/BufTextLen! + * + * @return Dirty + */ + public native boolean getBufDirty(); /* + return IMGUI_CALLBACK_DATA->BufDirty; + */ + + /** + * Set if you modify Buf/BufTextLen! + * + * @param dirty Dirty + */ + public native void setBufDirty(boolean dirty); /* + IMGUI_CALLBACK_DATA->BufDirty = dirty; + */ + + /** + * Current cursor position + * + * @return Current cursor position + */ + public native int getCursorPos(); /* + return IMGUI_CALLBACK_DATA->CursorPos; + */ + + /** + * Set the current cursor position + * + * @param pos Set the current cursor position + */ + public native void setCursorPos(int pos); /* + IMGUI_CALLBACK_DATA->CursorPos = pos; + */ + + /** + * Selection Start + * + * @return Selection Start + */ + public native int getSelectionStart(); /* + return IMGUI_CALLBACK_DATA->SelectionStart; + */ + + /** + * Set Selection Start + * + * @param pos Selection Start + */ + public native void setSelectionStart(int pos); /* + IMGUI_CALLBACK_DATA->SelectionStart = pos; + */ + + /** + * Selection End + * + * @return Selection End + */ + public native int getSelectionEnd(); /* + return IMGUI_CALLBACK_DATA->SelectionEnd; + */ + + /** + * Set Selection End + * + * @param pos Selection End + */ + public native void setSelectionEnd(int pos); /* + IMGUI_CALLBACK_DATA->SelectionEnd = pos; + */ + + /** + * Delete Chars + * + * @param pos Start Delete Pos + * @param bytesCount Delete Char Count + */ + public native void deleteChars(int pos, int bytesCount); /* + IMGUI_CALLBACK_DATA->DeleteChars(pos, bytesCount); + */ + + /** + * Insert Chars + * + * @param pos insert Psos + * @param str insert String + */ + public native void insertChars(int pos, String str); /* + IMGUI_CALLBACK_DATA->InsertChars(pos, str); + */ +} diff --git a/imgui-binding/src/main/java/imgui/callback/ImGuiInputTextCallback.java b/imgui-binding/src/main/java/imgui/callback/ImGuiInputTextCallback.java new file mode 100644 index 0000000..7cbc047 --- /dev/null +++ b/imgui-binding/src/main/java/imgui/callback/ImGuiInputTextCallback.java @@ -0,0 +1,17 @@ +package imgui.callback; + +import imgui.ImGuiInputTextCallbackData; + +import java.util.function.Consumer; + +/** + * Callback to use in {@link imgui.ImGui#inputText(String, imgui.type.ImString, int, ImGuiInputTextCallback)}. + */ +public abstract class ImGuiInputTextCallback implements Consumer { + /** + * This function will be called by the native Callback and wrapped. + */ + public final void accept(final long ptr) { + accept(new ImGuiInputTextCallbackData(ptr)); + } +} diff --git a/imgui-binding/src/main/java/imgui/flag/ImGuiInputTextFlags.java b/imgui-binding/src/main/java/imgui/flag/ImGuiInputTextFlags.java index 79d1b69..1f16cbe 100644 --- a/imgui-binding/src/main/java/imgui/flag/ImGuiInputTextFlags.java +++ b/imgui-binding/src/main/java/imgui/flag/ImGuiInputTextFlags.java @@ -86,4 +86,8 @@ public final class ImGuiInputTextFlags { * You will be provided a new BufSize in the callback and NEED to honor it. (see misc/cpp/imgui_stdlib.h for an example of using this) */ public static final int CallbackResize = 1 << 18; + /** + * Callback on any edit (note that InputText() already returns true on edit, the callback is useful mainly to manipulate the underlying buffer while focus is active). + */ + public static final int CallbackEdit = 1 << 19; }