From fbf1c0d1c2a204c37cc159088d1c9ffee3772a5f Mon Sep 17 00:00:00 2001 From: SpaiR Date: Wed, 1 Jan 2020 13:41:44 +0300 Subject: [PATCH] Add ImString resize support --- imgui-binding/src/main/java/imgui/ImGui.java | 144 +++++++++--------- .../main/java/imgui/ImGuiInputTextData.java | 25 ++- .../src/main/java/imgui/ImString.java | 67 ++++++-- .../src/test/java/ImGuiGlfwExample.java | 22 +-- 4 files changed, 155 insertions(+), 103 deletions(-) diff --git a/imgui-binding/src/main/java/imgui/ImGui.java b/imgui-binding/src/main/java/imgui/ImGui.java index 5cca24c..ad7d817 100644 --- a/imgui-binding/src/main/java/imgui/ImGui.java +++ b/imgui-binding/src/main/java/imgui/ImGui.java @@ -1,5 +1,7 @@ package imgui; +import imgui.enums.ImGuiInputTextFlags; + import java.nio.ByteBuffer; public final class ImGui { @@ -2382,25 +2384,26 @@ public final class ImGui { /*JNI jfieldID imTextInputDataSizeID; jfieldID imTextInputDataIsDirtyID; + jfieldID imTextInputDataIsResizedID; - struct InputTextCallback_UserData { - jobject* textInputData; + char* resizedBuf; + + struct InputTextCallbackUserData { JNIEnv* env; - int maxChar; - char* allowedChar; - int allowedCharLength; - int maxSize; - int curSize; + jobject* textInputData; + char* buf; + char* allowedChars; }; static int TextEditCallbackStub(ImGuiInputTextCallbackData* data) { - InputTextCallback_UserData* userData = (InputTextCallback_UserData*)data->UserData; + InputTextCallbackUserData* userData = (InputTextCallbackUserData*)data->UserData; if (data->EventFlag == ImGuiInputTextFlags_CallbackCharFilter) { - if(userData->allowedCharLength > 0) { + int allowedCharLength = strlen(userData->allowedChars); + if(allowedCharLength > 0) { bool found = false; - for(int i = 0; i < userData->allowedCharLength; i++) { - if(userData->allowedChar[i] == data->EventChar) { + for(int i = 0; i < allowedCharLength; i++) { + if(userData->allowedChars[i] == data->EventChar) { found = true; break; } @@ -2417,94 +2420,85 @@ public final class ImGui { jclass jImInputTextDataClass = env->FindClass("imgui/ImGuiInputTextData"); imTextInputDataSizeID = env->GetFieldID(jImInputTextDataClass, "size", "I"); imTextInputDataIsDirtyID = env->GetFieldID(jImInputTextDataClass, "isDirty", "Z"); + imTextInputDataIsResizedID = env->GetFieldID(jImInputTextDataClass, "isResized", "Z"); */ public static boolean InputText(String label, ImString text) { - return nInputText(label, text.data, text.data.length, 0, text.inputData, text.inputData.maxChar, text.inputData.allowedChar, text.inputData.allowedChar.length()); + return preInputText(false, label, text, 0, 0, 0); } public static boolean InputText(String label, ImString text, int imGuiInputTextFlags) { - return nInputText(label, text.data, text.data.length, imGuiInputTextFlags, text.inputData, text.inputData.maxChar, text.inputData.allowedChar, text.inputData.allowedChar.length()); + return preInputText(false, label, text, 0, 0, imGuiInputTextFlags); } - private static native boolean nInputText(String label, byte[] buff, int maxSize, int flags, ImGuiInputTextData textInputData, int maxChar, String allowedChar, int allowedCharLength); /* - int size = (int)strlen(buff); - - InputTextCallback_UserData cb_user_data; - cb_user_data.textInputData = &textInputData; - cb_user_data.env = env; - cb_user_data.curSize = size; - cb_user_data.maxSize = maxSize; - cb_user_data.maxChar = maxChar; - cb_user_data.allowedChar = allowedChar; - cb_user_data.allowedCharLength = allowedCharLength; - - char tempArray[maxSize]; - - memset(tempArray, 0, sizeof(tempArray)); - memcpy(tempArray, buff, size); - - if(maxChar >= 0 && maxChar < maxSize) { - maxSize = maxChar; - } - - bool flag = ImGui::InputText(label, tempArray, maxSize, flags | ImGuiInputTextFlags_CallbackCharFilter, &TextEditCallbackStub, &cb_user_data); - - if (flag) { - size = (int)strlen(tempArray); - env->SetIntField(textInputData, imTextInputDataSizeID, size); - env->SetBooleanField(textInputData, imTextInputDataIsDirtyID, true); - memset(buff, 0, maxSize); - memcpy(buff, tempArray, size); - } - - return flag; - */ - public static boolean InputTextMultiline(String label, ImString text) { - return nInputTextMultiline(label, text.data, text.data.length, 0, 0, 0, text.inputData, text.inputData.maxChar, text.inputData.allowedChar, text.inputData.allowedChar.length()); + return preInputText(true, label, text, 0, 0, 0); } public static boolean InputTextMultiline(String label, ImString text, float width, float height) { - return nInputTextMultiline(label, text.data, text.data.length, width, height, 0, text.inputData, text.inputData.maxChar, text.inputData.allowedChar, text.inputData.allowedChar.length()); + return preInputText(true, label, text, width, height, 0); + } + + public static boolean InputTextMultiline(String label, ImString text, int imGuiInputTextFlags) { + return preInputText(true, label, text, 0, 0, imGuiInputTextFlags); } public static boolean InputTextMultiline(String label, ImString text, float width, float height, int imGuiInputTextFlags) { - return nInputTextMultiline(label, text.data, text.data.length, width, height, imGuiInputTextFlags, text.inputData, text.inputData.maxChar, text.inputData.allowedChar, text.inputData.allowedChar.length()); + return preInputText(true, label, text, width, height, imGuiInputTextFlags); } - private static native boolean nInputTextMultiline(String label, byte[] buff, int maxSize, float width, float height, int flags, ImGuiInputTextData textInputData, int maxChar, String allowedChar, int allowedCharLength); /* - int size = (int)strlen(buff); + private static boolean preInputText(boolean multiline, String label, ImString text, float width, float height, int flags) { + ImGuiInputTextData inputData = text.inputData; - InputTextCallback_UserData cb_user_data; - cb_user_data.textInputData = &textInputData; - cb_user_data.env = env; - cb_user_data.curSize = size; - cb_user_data.maxSize = maxSize; - cb_user_data.maxChar = maxChar; - cb_user_data.allowedChar = allowedChar; - cb_user_data.allowedCharLength = allowedCharLength; - - char tempArray[maxSize]; - - memset(tempArray, 0, sizeof(tempArray)); - memcpy(tempArray, buff, size); - - if(maxChar >= 0 && maxChar < maxSize) { - maxSize = maxChar; + if (inputData.isResizable) { + flags |= ImGuiInputTextFlags.CallbackResize; } - bool flag = ImGui::InputTextMultiline(label, tempArray, maxSize, ImVec2(width, height), flags | ImGuiInputTextFlags_CallbackCharFilter, &TextEditCallbackStub, &cb_user_data); + boolean hasInput = nInputText(multiline, label, text.data, text.data.length, width, height, flags, inputData, inputData.allowedChars); + + if (inputData.isResized) { + inputData.isResized = false; + text.set(nGetResizedStr(), true); + } + + return hasInput; + } + + private static native boolean nInputText(boolean multiline, String label, byte[] buf, int maxSize, float width, float height, int flags, ImGuiInputTextData textInputData, String allowedChars); /* + InputTextCallbackUserData userData; + userData.textInputData = &textInputData; + userData.env = env; + userData.buf = buf; + userData.allowedChars = allowedChars; + + if (strlen(allowedChars) > 0) + flags |= ImGuiInputTextFlags_CallbackCharFilter; + + bool hasInput; + + if (multiline) { + hasInput = ImGui::InputTextMultiline(label, buf, maxSize, ImVec2(width, height), flags, &TextEditCallbackStub, &userData); + } else { + hasInput = ImGui::InputText(label, buf, maxSize, flags, &TextEditCallbackStub, &userData); + } + + if (hasInput) { + int size = strlen(buf); + + if (((size + 1) > maxSize) && (flags & ImGuiInputTextFlags_CallbackResize)) { + env->SetBooleanField(textInputData, imTextInputDataIsResizedID, true); + resizedBuf = buf; + } - if (flag) { - size = (int)strlen(tempArray); env->SetIntField(textInputData, imTextInputDataSizeID, size); env->SetBooleanField(textInputData, imTextInputDataIsDirtyID, true); - memset(buff, 0, maxSize); - memcpy(buff, tempArray, size); } - return flag; + return hasInput; + */ + + private static native String nGetResizedStr(); /* + return env->NewStringUTF(resizedBuf); */ public static boolean InputFloat(String label, ImFloat v) { @@ -4522,7 +4516,7 @@ public final class ImGui { */ // Clipboard Utilities (also see the LogToClipboard() function to capture or output text data to the clipboard) - + public static native String GetClipboardText(); /* return env->NewStringUTF(ImGui::GetClipboardText()); */ diff --git a/imgui-binding/src/main/java/imgui/ImGuiInputTextData.java b/imgui-binding/src/main/java/imgui/ImGuiInputTextData.java index 3457de6..86bbf61 100644 --- a/imgui-binding/src/main/java/imgui/ImGuiInputTextData.java +++ b/imgui-binding/src/main/java/imgui/ImGuiInputTextData.java @@ -1,8 +1,25 @@ package imgui; -final class ImGuiInputTextData { - public int size; - public int maxChar = -1; - public String allowedChar = ""; +/** + * Use this class to customize your ImGui input. + */ +public final class ImGuiInputTextData { + /** + * If not empty, then other chars which are different from provided will be filtered during the {@link ImGui#InputText(String, ImString)} + * and {@link ImGui#InputTextMultiline} methods. + */ + public String allowedChars = ""; + + /** + * If true, then string will be resized during the the {@link ImGui#InputText(String, ImString)} and {@link ImGui#InputTextMultiline} methods. + * Alternatively you can provide {@link imgui.enums.ImGuiInputTextFlags#CallbackResize} flag to the input text widgets to enable string resizing. + */ + public boolean isResizable; + + int size; boolean isDirty; + boolean isResized = false; + + ImGuiInputTextData() { + } } diff --git a/imgui-binding/src/main/java/imgui/ImString.java b/imgui-binding/src/main/java/imgui/ImString.java index 818457e..86490ae 100644 --- a/imgui-binding/src/main/java/imgui/ImString.java +++ b/imgui-binding/src/main/java/imgui/ImString.java @@ -1,20 +1,30 @@ package imgui; -import java.util.Arrays; +import java.util.Objects; +/** + * Wrapper for {@link String} to use inside of ImGui input widgets. + */ public final class ImString { - private static final int DEFAULT_SIZE = 100; + private static final short DEFAULT_LENGTH = 100; + private static final short CARET_LEN = 1; + private static final short DEFAULT_RESIZE = 10; + + public final ImGuiInputTextData inputData = new ImGuiInputTextData(); + /** + * String will be resized to the value equal to a new size plus this resize factor. + */ + public int resizeFactor = DEFAULT_RESIZE; - ImGuiInputTextData inputData = new ImGuiInputTextData(); byte[] data; - private String text; + private String text = ""; public ImString() { - this(DEFAULT_SIZE); + this(DEFAULT_LENGTH); } - public ImString(int size) { - data = new byte[size]; + public ImString(int length) { + data = new byte[length + CARET_LEN]; } public ImString(String text) { @@ -22,8 +32,8 @@ public final class ImString { set(text); } - public ImString(String text, int size) { - this(size); + public ImString(String text, int length) { + this(length); set(text); } @@ -36,11 +46,38 @@ public final class ImString { } public void set(String value) { - inputData.size = value.length(); - text = value; - for (int i = 0; i < inputData.size; i++) { - data[i] = (byte) value.charAt(i); + set(value.getBytes()); + } + + public void set(String value, boolean resize) { + byte[] str = value.getBytes(); + if (resize && data.length - CARET_LEN < str.length) { + data = new byte[str.length + resizeFactor + CARET_LEN]; } + set(str); + } + + /** + * Get the length of the text inside of the data buffer. + * @return length of the text inside of the data buffer + */ + public int getLength() { + return get().length(); + } + + /** + * Get the size of the data buffer. Buffer size will always have '+1' to its size, since it's used by the Dear ImGui to draw a caret. + * @return size of the data buffer + */ + public int getBufferSize() { + return data.length; + } + + private void set(byte[] str) { + int len = Math.min(str.length, data.length); + System.arraycopy(str, 0, data, 0, len); + inputData.isDirty = true; + inputData.size = len; } @Override @@ -53,11 +90,11 @@ public final class ImString { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; ImString imString = (ImString) o; - return Arrays.equals(data, imString.data); + return Objects.equals(text, imString.text); } @Override public int hashCode() { - return Arrays.hashCode(data); + return text.hashCode(); } } diff --git a/imgui-lwjgl3/src/test/java/ImGuiGlfwExample.java b/imgui-lwjgl3/src/test/java/ImGuiGlfwExample.java index d40bf73..a8b2367 100644 --- a/imgui-lwjgl3/src/test/java/ImGuiGlfwExample.java +++ b/imgui-lwjgl3/src/test/java/ImGuiGlfwExample.java @@ -47,11 +47,12 @@ public final class ImGuiGlfwExample { private final ImGuiImplGl3 imGuiGl3 = new ImGuiImplGl3(); // Local app variables go here - private final ImString imguiDemoLink = new ImString("https://raw.githubusercontent.com/ocornut/imgui/v1.74/imgui_demo.cpp", 100); - private float[] backgroundColor = new float[]{0.5f, 0, 0}; - private int clickCount = 0; + private final String imguiDemoLink = "https://raw.githubusercontent.com/ocornut/imgui/v1.74/imgui_demo.cpp"; private final byte[] testPayload = "Test Payload".getBytes(); private String dropTargetText = "Drop Here"; + private float[] backgroundColor = new float[]{0.5f, 0, 0}; + private int clickCount = 0; + private final ImString resizableStr = new ImString(5); private final ImBool showDemoWindow = new ImBool(); @@ -273,11 +274,12 @@ public final class ImGuiGlfwExample { } private void showUi() { - ImGui.SetNextWindowSize(600, 210, ImGuiCond.Once); + ImGui.SetNextWindowSize(600, 300, ImGuiCond.Once); ImGui.SetNextWindowPos(10, 10, ImGuiCond.Once); ImGui.Begin("Custom window"); ImGui.Text("Hello from Java!"); + ImGui.Button("Drag me"); if (ImGui.BeginDragDropSource()) { ImGui.SetDragDropPayload("payload_type", testPayload, testPayload.length); @@ -298,6 +300,7 @@ public final class ImGuiGlfwExample { ImGui.Text("Background color:"); ImGui.SameLine(); ImGui.ColorEdit3("##click_counter_col", backgroundColor, ImGuiColorEditFlags.NoInputs | ImGuiColorEditFlags.NoDragDrop); + if (ImGui.Button("Click")) { clickCount++; } @@ -309,16 +312,17 @@ public final class ImGuiGlfwExample { ImGui.Checkbox("Show demo window", showDemoWindow); ImGui.NewLine(); + ImGui.InputText("Resizable input", resizableStr, ImGuiInputTextFlags.CallbackResize); + ImGui.Text(String.format("text len: %d | buffer size: %d", resizableStr.getLength(), resizableStr.getBufferSize())); + ImGui.NewLine(); + ImGui.Separator(); ImGui.Text("Consider to look the original ImGui demo: "); ImGui.SetNextItemWidth(500); - ImGui.InputText("##input_to_copy_link", imguiDemoLink, ImGuiInputTextFlags.ReadOnly); - if (ImGui.IsItemHovered()) { - ImGui.SetMouseCursor(ImGuiMouseCursor.TextInput); - } + ImGui.TextColored(0, .8f, 0, 1, imguiDemoLink); ImGui.SameLine(); if (ImGui.Button("Copy")) { - ImGui.SetClipboardText(imguiDemoLink.get()); + ImGui.SetClipboardText(imguiDemoLink); } }