Skip to content

Commit fbf1c0d

Browse files
committed
Add ImString resize support
1 parent 2954719 commit fbf1c0d

File tree

4 files changed

+151
-99
lines changed

4 files changed

+151
-99
lines changed

imgui-binding/src/main/java/imgui/ImGui.java

Lines changed: 65 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package imgui;
22

3+
import imgui.enums.ImGuiInputTextFlags;
4+
35
import java.nio.ByteBuffer;
46

57
public final class ImGui {
@@ -2382,25 +2384,26 @@ public static boolean VSliderScalar(String label, float sizeX, float sizeY, int
23822384
/*JNI
23832385
jfieldID imTextInputDataSizeID;
23842386
jfieldID imTextInputDataIsDirtyID;
2387+
jfieldID imTextInputDataIsResizedID;
23852388
2386-
struct InputTextCallback_UserData {
2387-
jobject* textInputData;
2389+
char* resizedBuf;
2390+
2391+
struct InputTextCallbackUserData {
23882392
JNIEnv* env;
2389-
int maxChar;
2390-
char* allowedChar;
2391-
int allowedCharLength;
2392-
int maxSize;
2393-
int curSize;
2393+
jobject* textInputData;
2394+
char* buf;
2395+
char* allowedChars;
23942396
};
23952397
23962398
static int TextEditCallbackStub(ImGuiInputTextCallbackData* data) {
2397-
InputTextCallback_UserData* userData = (InputTextCallback_UserData*)data->UserData;
2399+
InputTextCallbackUserData* userData = (InputTextCallbackUserData*)data->UserData;
23982400
23992401
if (data->EventFlag == ImGuiInputTextFlags_CallbackCharFilter) {
2400-
if(userData->allowedCharLength > 0) {
2402+
int allowedCharLength = strlen(userData->allowedChars);
2403+
if(allowedCharLength > 0) {
24012404
bool found = false;
2402-
for(int i = 0; i < userData->allowedCharLength; i++) {
2403-
if(userData->allowedChar[i] == data->EventChar) {
2405+
for(int i = 0; i < allowedCharLength; i++) {
2406+
if(userData->allowedChars[i] == data->EventChar) {
24042407
found = true;
24052408
break;
24062409
}
@@ -2417,94 +2420,85 @@ static int TextEditCallbackStub(ImGuiInputTextCallbackData* data) {
24172420
jclass jImInputTextDataClass = env->FindClass("imgui/ImGuiInputTextData");
24182421
imTextInputDataSizeID = env->GetFieldID(jImInputTextDataClass, "size", "I");
24192422
imTextInputDataIsDirtyID = env->GetFieldID(jImInputTextDataClass, "isDirty", "Z");
2423+
imTextInputDataIsResizedID = env->GetFieldID(jImInputTextDataClass, "isResized", "Z");
24202424
*/
24212425

24222426
public static boolean InputText(String label, ImString text) {
2423-
return nInputText(label, text.data, text.data.length, 0, text.inputData, text.inputData.maxChar, text.inputData.allowedChar, text.inputData.allowedChar.length());
2427+
return preInputText(false, label, text, 0, 0, 0);
24242428
}
24252429

24262430
public static boolean InputText(String label, ImString text, int imGuiInputTextFlags) {
2427-
return nInputText(label, text.data, text.data.length, imGuiInputTextFlags, text.inputData, text.inputData.maxChar, text.inputData.allowedChar, text.inputData.allowedChar.length());
2431+
return preInputText(false, label, text, 0, 0, imGuiInputTextFlags);
24282432
}
24292433

2430-
private static native boolean nInputText(String label, byte[] buff, int maxSize, int flags, ImGuiInputTextData textInputData, int maxChar, String allowedChar, int allowedCharLength); /*
2431-
int size = (int)strlen(buff);
2432-
2433-
InputTextCallback_UserData cb_user_data;
2434-
cb_user_data.textInputData = &textInputData;
2435-
cb_user_data.env = env;
2436-
cb_user_data.curSize = size;
2437-
cb_user_data.maxSize = maxSize;
2438-
cb_user_data.maxChar = maxChar;
2439-
cb_user_data.allowedChar = allowedChar;
2440-
cb_user_data.allowedCharLength = allowedCharLength;
2434+
public static boolean InputTextMultiline(String label, ImString text) {
2435+
return preInputText(true, label, text, 0, 0, 0);
2436+
}
24412437

2442-
char tempArray[maxSize];
2438+
public static boolean InputTextMultiline(String label, ImString text, float width, float height) {
2439+
return preInputText(true, label, text, width, height, 0);
2440+
}
24432441

2444-
memset(tempArray, 0, sizeof(tempArray));
2445-
memcpy(tempArray, buff, size);
2442+
public static boolean InputTextMultiline(String label, ImString text, int imGuiInputTextFlags) {
2443+
return preInputText(true, label, text, 0, 0, imGuiInputTextFlags);
2444+
}
24462445

2447-
if(maxChar >= 0 && maxChar < maxSize) {
2448-
maxSize = maxChar;
2449-
}
2446+
public static boolean InputTextMultiline(String label, ImString text, float width, float height, int imGuiInputTextFlags) {
2447+
return preInputText(true, label, text, width, height, imGuiInputTextFlags);
2448+
}
24502449

2451-
bool flag = ImGui::InputText(label, tempArray, maxSize, flags | ImGuiInputTextFlags_CallbackCharFilter, &TextEditCallbackStub, &cb_user_data);
2450+
private static boolean preInputText(boolean multiline, String label, ImString text, float width, float height, int flags) {
2451+
ImGuiInputTextData inputData = text.inputData;
24522452

2453-
if (flag) {
2454-
size = (int)strlen(tempArray);
2455-
env->SetIntField(textInputData, imTextInputDataSizeID, size);
2456-
env->SetBooleanField(textInputData, imTextInputDataIsDirtyID, true);
2457-
memset(buff, 0, maxSize);
2458-
memcpy(buff, tempArray, size);
2453+
if (inputData.isResizable) {
2454+
flags |= ImGuiInputTextFlags.CallbackResize;
24592455
}
24602456

2461-
return flag;
2462-
*/
2463-
2464-
public static boolean InputTextMultiline(String label, ImString text) {
2465-
return nInputTextMultiline(label, text.data, text.data.length, 0, 0, 0, text.inputData, text.inputData.maxChar, text.inputData.allowedChar, text.inputData.allowedChar.length());
2466-
}
2457+
boolean hasInput = nInputText(multiline, label, text.data, text.data.length, width, height, flags, inputData, inputData.allowedChars);
24672458

2468-
public static boolean InputTextMultiline(String label, ImString text, float width, float height) {
2469-
return nInputTextMultiline(label, text.data, text.data.length, width, height, 0, text.inputData, text.inputData.maxChar, text.inputData.allowedChar, text.inputData.allowedChar.length());
2470-
}
2459+
if (inputData.isResized) {
2460+
inputData.isResized = false;
2461+
text.set(nGetResizedStr(), true);
2462+
}
24712463

2472-
public static boolean InputTextMultiline(String label, ImString text, float width, float height, int imGuiInputTextFlags) {
2473-
return nInputTextMultiline(label, text.data, text.data.length, width, height, imGuiInputTextFlags, text.inputData, text.inputData.maxChar, text.inputData.allowedChar, text.inputData.allowedChar.length());
2464+
return hasInput;
24742465
}
24752466

2476-
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); /*
2477-
int size = (int)strlen(buff);
2478-
2479-
InputTextCallback_UserData cb_user_data;
2480-
cb_user_data.textInputData = &textInputData;
2481-
cb_user_data.env = env;
2482-
cb_user_data.curSize = size;
2483-
cb_user_data.maxSize = maxSize;
2484-
cb_user_data.maxChar = maxChar;
2485-
cb_user_data.allowedChar = allowedChar;
2486-
cb_user_data.allowedCharLength = allowedCharLength;
2467+
private static native boolean nInputText(boolean multiline, String label, byte[] buf, int maxSize, float width, float height, int flags, ImGuiInputTextData textInputData, String allowedChars); /*
2468+
InputTextCallbackUserData userData;
2469+
userData.textInputData = &textInputData;
2470+
userData.env = env;
2471+
userData.buf = buf;
2472+
userData.allowedChars = allowedChars;
24872473
2488-
char tempArray[maxSize];
2474+
if (strlen(allowedChars) > 0)
2475+
flags |= ImGuiInputTextFlags_CallbackCharFilter;
24892476
2490-
memset(tempArray, 0, sizeof(tempArray));
2491-
memcpy(tempArray, buff, size);
2477+
bool hasInput;
24922478
2493-
if(maxChar >= 0 && maxChar < maxSize) {
2494-
maxSize = maxChar;
2479+
if (multiline) {
2480+
hasInput = ImGui::InputTextMultiline(label, buf, maxSize, ImVec2(width, height), flags, &TextEditCallbackStub, &userData);
2481+
} else {
2482+
hasInput = ImGui::InputText(label, buf, maxSize, flags, &TextEditCallbackStub, &userData);
24952483
}
24962484
2497-
bool flag = ImGui::InputTextMultiline(label, tempArray, maxSize, ImVec2(width, height), flags | ImGuiInputTextFlags_CallbackCharFilter, &TextEditCallbackStub, &cb_user_data);
2485+
if (hasInput) {
2486+
int size = strlen(buf);
2487+
2488+
if (((size + 1) > maxSize) && (flags & ImGuiInputTextFlags_CallbackResize)) {
2489+
env->SetBooleanField(textInputData, imTextInputDataIsResizedID, true);
2490+
resizedBuf = buf;
2491+
}
24982492
2499-
if (flag) {
2500-
size = (int)strlen(tempArray);
25012493
env->SetIntField(textInputData, imTextInputDataSizeID, size);
25022494
env->SetBooleanField(textInputData, imTextInputDataIsDirtyID, true);
2503-
memset(buff, 0, maxSize);
2504-
memcpy(buff, tempArray, size);
25052495
}
25062496
2507-
return flag;
2497+
return hasInput;
2498+
*/
2499+
2500+
private static native String nGetResizedStr(); /*
2501+
return env->NewStringUTF(resizedBuf);
25082502
*/
25092503

25102504
public static boolean InputFloat(String label, ImFloat v) {
@@ -4522,7 +4516,7 @@ public static ImDrawList GetForegroundDrawList() {
45224516
*/
45234517

45244518
// Clipboard Utilities (also see the LogToClipboard() function to capture or output text data to the clipboard)
4525-
4519+
45264520
public static native String GetClipboardText(); /*
45274521
return env->NewStringUTF(ImGui::GetClipboardText());
45284522
*/
Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,25 @@
11
package imgui;
22

3-
final class ImGuiInputTextData {
4-
public int size;
5-
public int maxChar = -1;
6-
public String allowedChar = "";
3+
/**
4+
* Use this class to customize your ImGui input.
5+
*/
6+
public final class ImGuiInputTextData {
7+
/**
8+
* If not empty, then other chars which are different from provided will be filtered during the {@link ImGui#InputText(String, ImString)}
9+
* and {@link ImGui#InputTextMultiline} methods.
10+
*/
11+
public String allowedChars = "";
12+
13+
/**
14+
* If true, then string will be resized during the the {@link ImGui#InputText(String, ImString)} and {@link ImGui#InputTextMultiline} methods.
15+
* Alternatively you can provide {@link imgui.enums.ImGuiInputTextFlags#CallbackResize} flag to the input text widgets to enable string resizing.
16+
*/
17+
public boolean isResizable;
18+
19+
int size;
720
boolean isDirty;
21+
boolean isResized = false;
22+
23+
ImGuiInputTextData() {
24+
}
825
}
Lines changed: 52 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,39 @@
11
package imgui;
22

3-
import java.util.Arrays;
3+
import java.util.Objects;
44

5+
/**
6+
* Wrapper for {@link String} to use inside of ImGui input widgets.
7+
*/
58
public final class ImString {
6-
private static final int DEFAULT_SIZE = 100;
9+
private static final short DEFAULT_LENGTH = 100;
10+
private static final short CARET_LEN = 1;
11+
private static final short DEFAULT_RESIZE = 10;
12+
13+
public final ImGuiInputTextData inputData = new ImGuiInputTextData();
14+
/**
15+
* String will be resized to the value equal to a new size plus this resize factor.
16+
*/
17+
public int resizeFactor = DEFAULT_RESIZE;
718

8-
ImGuiInputTextData inputData = new ImGuiInputTextData();
919
byte[] data;
10-
private String text;
20+
private String text = "";
1121

1222
public ImString() {
13-
this(DEFAULT_SIZE);
23+
this(DEFAULT_LENGTH);
1424
}
1525

16-
public ImString(int size) {
17-
data = new byte[size];
26+
public ImString(int length) {
27+
data = new byte[length + CARET_LEN];
1828
}
1929

2030
public ImString(String text) {
2131
this(text.length());
2232
set(text);
2333
}
2434

25-
public ImString(String text, int size) {
26-
this(size);
35+
public ImString(String text, int length) {
36+
this(length);
2737
set(text);
2838
}
2939

@@ -36,11 +46,38 @@ public String get() {
3646
}
3747

3848
public void set(String value) {
39-
inputData.size = value.length();
40-
text = value;
41-
for (int i = 0; i < inputData.size; i++) {
42-
data[i] = (byte) value.charAt(i);
49+
set(value.getBytes());
50+
}
51+
52+
public void set(String value, boolean resize) {
53+
byte[] str = value.getBytes();
54+
if (resize && data.length - CARET_LEN < str.length) {
55+
data = new byte[str.length + resizeFactor + CARET_LEN];
4356
}
57+
set(str);
58+
}
59+
60+
/**
61+
* Get the length of the text inside of the data buffer.
62+
* @return length of the text inside of the data buffer
63+
*/
64+
public int getLength() {
65+
return get().length();
66+
}
67+
68+
/**
69+
* 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.
70+
* @return size of the data buffer
71+
*/
72+
public int getBufferSize() {
73+
return data.length;
74+
}
75+
76+
private void set(byte[] str) {
77+
int len = Math.min(str.length, data.length);
78+
System.arraycopy(str, 0, data, 0, len);
79+
inputData.isDirty = true;
80+
inputData.size = len;
4481
}
4582

4683
@Override
@@ -53,11 +90,11 @@ public boolean equals(Object o) {
5390
if (this == o) return true;
5491
if (o == null || getClass() != o.getClass()) return false;
5592
ImString imString = (ImString) o;
56-
return Arrays.equals(data, imString.data);
93+
return Objects.equals(text, imString.text);
5794
}
5895

5996
@Override
6097
public int hashCode() {
61-
return Arrays.hashCode(data);
98+
return text.hashCode();
6299
}
63100
}

imgui-lwjgl3/src/test/java/ImGuiGlfwExample.java

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,12 @@ public final class ImGuiGlfwExample {
4747
private final ImGuiImplGl3 imGuiGl3 = new ImGuiImplGl3();
4848

4949
// Local app variables go here
50-
private final ImString imguiDemoLink = new ImString("https://raw.githubusercontent.com/ocornut/imgui/v1.74/imgui_demo.cpp", 100);
51-
private float[] backgroundColor = new float[]{0.5f, 0, 0};
52-
private int clickCount = 0;
50+
private final String imguiDemoLink = "https://raw.githubusercontent.com/ocornut/imgui/v1.74/imgui_demo.cpp";
5351
private final byte[] testPayload = "Test Payload".getBytes();
5452
private String dropTargetText = "Drop Here";
53+
private float[] backgroundColor = new float[]{0.5f, 0, 0};
54+
private int clickCount = 0;
55+
private final ImString resizableStr = new ImString(5);
5556

5657
private final ImBool showDemoWindow = new ImBool();
5758

@@ -273,11 +274,12 @@ private void loop() {
273274
}
274275

275276
private void showUi() {
276-
ImGui.SetNextWindowSize(600, 210, ImGuiCond.Once);
277+
ImGui.SetNextWindowSize(600, 300, ImGuiCond.Once);
277278
ImGui.SetNextWindowPos(10, 10, ImGuiCond.Once);
278279

279280
ImGui.Begin("Custom window");
280281
ImGui.Text("Hello from Java!");
282+
281283
ImGui.Button("Drag me");
282284
if (ImGui.BeginDragDropSource()) {
283285
ImGui.SetDragDropPayload("payload_type", testPayload, testPayload.length);
@@ -298,6 +300,7 @@ private void showUi() {
298300
ImGui.Text("Background color:");
299301
ImGui.SameLine();
300302
ImGui.ColorEdit3("##click_counter_col", backgroundColor, ImGuiColorEditFlags.NoInputs | ImGuiColorEditFlags.NoDragDrop);
303+
301304
if (ImGui.Button("Click")) {
302305
clickCount++;
303306
}
@@ -309,16 +312,17 @@ private void showUi() {
309312
ImGui.Checkbox("Show demo window", showDemoWindow);
310313
ImGui.NewLine();
311314

315+
ImGui.InputText("Resizable input", resizableStr, ImGuiInputTextFlags.CallbackResize);
316+
ImGui.Text(String.format("text len: %d | buffer size: %d", resizableStr.getLength(), resizableStr.getBufferSize()));
317+
ImGui.NewLine();
318+
312319
ImGui.Separator();
313320
ImGui.Text("Consider to look the original ImGui demo: ");
314321
ImGui.SetNextItemWidth(500);
315-
ImGui.InputText("##input_to_copy_link", imguiDemoLink, ImGuiInputTextFlags.ReadOnly);
316-
if (ImGui.IsItemHovered()) {
317-
ImGui.SetMouseCursor(ImGuiMouseCursor.TextInput);
318-
}
322+
ImGui.TextColored(0, .8f, 0, 1, imguiDemoLink);
319323
ImGui.SameLine();
320324
if (ImGui.Button("Copy")) {
321-
ImGui.SetClipboardText(imguiDemoLink.get());
325+
ImGui.SetClipboardText(imguiDemoLink);
322326
}
323327
}
324328

0 commit comments

Comments
 (0)