Skip to content

Commit 342ac7b

Browse files
edoliCopilot
andauthored
feat: restore ImGuiColorTextEdit support (#389)
Switch the vendored ImGuiColorTextEdit extension from BalazsJako's repository to goossens' actively maintained implementation and regenerate the text editor bindings against the current API. Re-enable the Java example and require C++17 for native builds because the new upstream code depends on it. Closes #360 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 7c06865 commit 342ac7b

29 files changed

Lines changed: 2413 additions & 594 deletions

.gitmodules

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
url = https://github.com/epezent/implot.git
1313
[submodule "include/ImGuiColorTextEdit"]
1414
path = include/ImGuiColorTextEdit
15-
url = https://github.com/BalazsJako/ImGuiColorTextEdit
15+
url = https://github.com/goossens/ImGuiColorTextEdit
1616
[submodule "include/ImGuiFileDialog"]
1717
path = include/ImGuiFileDialog
1818
url = https://github.com/aiekick/ImGuiFileDialog

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,7 @@ See examples in the `example` module for more information about how to use them.
324324
Immediate mode 3D gizmo for scene editing and other controls based on Dear ImGui.
325325
- [implot](https://github.com/epezent/implot/tree/v1.0) | [Example](https://github.com/SpaiR/imgui-java/blob/main/example/src/main/java/ExampleImPlot.java) <br>
326326
Advanced 2D Plotting for Dear ImGui.
327-
- [ImGuiColorTextEdit](https://github.com/BalazsJako/ImGuiColorTextEdit/tree/0a88824f7de8d0bd11d8419066caa7d3469395c4) | [Example](https://github.com/SpaiR/imgui-java/blob/main/example/src/main/java/ExampleImGuiColorTextEdit.java) <br>
327+
- [ImGuiColorTextEdit](https://github.com/goossens/ImGuiColorTextEdit/tree/0a88824f7de8d0bd11d8419066caa7d3469395c4) | [Example](https://github.com/SpaiR/imgui-java/blob/main/example/src/main/java/ExampleImGuiColorTextEdit.java) <br>
328328
Syntax highlighting text editor for ImGui.
329329
- [ImGuiFileDialog](https://github.com/aiekick/ImGuiFileDialog/tree/4d42dfba125cbd4780a90fbc5f75e7dfbae64060) | [Example](https://github.com/SpaiR/imgui-java/blob/main/example/src/main/java/ExampleImGuiFileDialog.java) <br>
330330
A file selection dialog built for ImGui.

buildSrc/src/main/groovy/tool/generator/GenerateLibs.groovy

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class GenerateLibs extends DefaultTask {
1818
'include/imgui-node-editor',
1919
'include/imguizmo',
2020
'include/implot',
21-
// 'include/ImGuiColorTextEdit',
21+
'include/ImGuiColorTextEdit',
2222
// 'include/ImGuiFileDialog',
2323
'include/imgui_club/imgui_memory_editor',
2424
'include/imgui-knobs'
@@ -80,6 +80,12 @@ class GenerateLibs extends DefaultTask {
8080
spec.into(jniDir)
8181
}
8282

83+
// Ensure the active ImGuiColorTextEdit snapshot wins even if a stale TextEditor.* exists in the JNI dir.
84+
project.copy { CopySpec spec ->
85+
spec.from(project.rootProject.file('include/ImGuiColorTextEdit')) { CopySpec s -> s.include('TextEditor.h', 'TextEditor.cpp') }
86+
spec.into(jniDir)
87+
}
88+
8389
if (withFreeType) {
8490
project.copy { CopySpec spec ->
8591
spec.from(project.rootProject.file('include/imgui/misc/freetype')) { CopySpec it -> it.include('*.h', '*.cpp') }
@@ -108,12 +114,14 @@ class GenerateLibs extends DefaultTask {
108114

109115
if (forWindows) {
110116
def win64 = BuildTarget.newDefaultTarget(Os.Windows, Architecture.Bitness._64)
117+
requireCpp17(win64)
111118
addFreeTypeIfEnabled(win64)
112119
buildTargets += win64
113120
}
114121

115122
if (forLinux) {
116123
def linux64 = BuildTarget.newDefaultTarget(Os.Linux, Architecture.Bitness._64)
124+
requireCpp17(linux64)
117125
addFreeTypeIfEnabled(linux64)
118126
buildTargets += linux64
119127
}
@@ -166,13 +174,20 @@ class GenerateLibs extends DefaultTask {
166174
def minMacOsVersion = '10.15'
167175
def macTarget = BuildTarget.newDefaultTarget(Os.MacOsX, Architecture.Bitness._64, arch)
168176
macTarget.libName = "libimgui-java64.dylib" // Lib for arm64 will be named the same for consistency.
169-
macTarget.cppFlags += ' -std=c++14'
177+
requireCpp17(macTarget)
170178
macTarget.cppFlags = macTarget.cppFlags.replace('10.7', minMacOsVersion)
171179
macTarget.linkerFlags = macTarget.linkerFlags.replace('10.7', minMacOsVersion)
172180
addFreeTypeIfEnabled(macTarget)
173181
return macTarget
174182
}
175183

184+
void requireCpp17(BuildTarget target) {
185+
target.cppFlags = target.cppFlags.replace(' -std=c++14', '')
186+
if (!target.cppFlags.contains('-std=c++17')) {
187+
target.cppFlags += ' -std=c++17'
188+
}
189+
}
190+
176191
void addFreeTypeIfEnabled(BuildTarget target) {
177192
if (!withFreeType) {
178193
return

buildSrc/src/main/kotlin/tool/generator/api/jni_content.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ private fun convertParams2jni(f: Factory, params: List<CtParameter<*>>, defaults
9797
setType<CtTypedElement<Any>>(f.createTypeParam("double"))
9898
setSimpleName<CtNamedElement>("${p.simpleName}MaxY")
9999
}
100-
} else if (p.isType("TextEditorCoordinates")) {
100+
} else if (p.isType("TextEditorCursorPosition")) {
101101
result += f.createParameter<Any>().apply {
102102
setType<CtTypedElement<Any>>(f.createTypeParam("int"))
103103
setSimpleName<CtNamedElement>("${p.simpleName}Line")
@@ -167,8 +167,8 @@ private fun joinInBodyParams(params: List<CtParameter<*>>, defaults: IntArray):
167167
"ImPlotRect(${p.simpleName}MinX, ${p.simpleName}MinY, ${p.simpleName}MaxX, ${p.simpleName}MaxY)"
168168
}
169169

170-
"TextEditorCoordinates" -> {
171-
"TextEditor::Coordinates(${p.simpleName}Line, ${p.simpleName}Column)"
170+
"TextEditorCursorPosition" -> {
171+
"TextEditor::CursorPosition(${p.simpleName}Line, ${p.simpleName}Column)"
172172
}
173173

174174
else -> p.simpleName

buildSrc/src/main/kotlin/tool/generator/api/jvm_content.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ private fun joinInBodyParams(params: List<CtParameter<*>>, defaults: IntArray):
4242
"ImPlotRange" -> "${p.simpleName}.min, ${p.simpleName}.max"
4343
"ImPlotRect" -> "${p.simpleName}.x.min, ${p.simpleName}.y.min, ${p.simpleName}.x.max, ${p.simpleName}.y.max"
4444

45-
"TextEditorCoordinates" -> "${p.simpleName}.mLine, ${p.simpleName}.mColumn"
45+
"TextEditorCursorPosition" -> "${p.simpleName}.line, ${p.simpleName}.column"
4646

4747
"String[]" -> "${p.simpleName}, ${p.simpleName}.length"
4848

@@ -425,7 +425,7 @@ private fun methodCoordinatesUnwrappedContent(method: CtMethod<*>, fromIndex: In
425425
val paramNames = mutableSetOf<String>()
426426

427427
for ((idx, p) in newMethod.parameters.withIndex()) {
428-
if (p.isType("TextEditorCoordinates") && idx >= fromIndex) {
428+
if (p.isType("TextEditorCursorPosition") && idx >= fromIndex) {
429429
paramNames += p.simpleName
430430

431431
val paramX = p.factory.createParameter<Any>()
@@ -529,7 +529,7 @@ private fun transformMethodToContent(
529529
if (params.find { it.isType("ImPlotRect") } != null) {
530530
methodPlotLimitsUnwrappedContent(method, fromIndex).takeIf(String::isNotEmpty)?.run(result::add)
531531
}
532-
if (params.find { it.isType("TextEditorCoordinates") } != null) {
532+
if (params.find { it.isType("TextEditorCursorPosition") } != null) {
533533
methodCoordinatesUnwrappedContent(method, fromIndex).takeIf(String::isNotEmpty)?.run(result::add)
534534
}
535535
return result

buildSrc/src/main/kotlin/tool/generator/api/util.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,8 @@ val DST_RETURN_TYPE_SET = setOf(
8181
"ImPlotPoint",
8282
"ImPlotRange",
8383
"ImPlotRect",
84-
"TextEditorCoordinates",
84+
"TextEditorCursorPosition",
85+
"TextEditorCursorSelection",
8586
)
8687

8788
fun CtElement.hasAnnotation(annotationName: String): Boolean {

buildSrc/src/main/resources/generator/api/ast/ast-TextEditor.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"info" : {
33
"source" : "include/ImGuiColorTextEdit/TextEditor.h",
44
"hash" : "1e5c6cd321f415c393ab30d4800a0dc2",
5-
"url" : "https://github.com/BalazsJako/ImGuiColorTextEdit",
5+
"url" : "https://github.com/goossens/ImGuiColorTextEdit",
66
"revision" : "0a88824f7de8d0bd11d8419066caa7d3469395c4"
77
},
88
"decls" : [ {
Lines changed: 49 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1,82 +1,49 @@
1-
/*
21
import imgui.ImGui;
32
import imgui.extension.texteditor.TextEditor;
4-
import imgui.extension.texteditor.TextEditorCoordinates;
5-
import imgui.extension.texteditor.TextEditorLanguageDefinition;
3+
import imgui.extension.texteditor.TextEditorCursorPosition;
4+
import imgui.extension.texteditor.TextEditorLanguage;
5+
import imgui.extension.texteditor.flag.TextEditorColor;
6+
import imgui.extension.texteditor.flag.TextEditorScroll;
7+
import imgui.flag.ImGuiCond;
68
import imgui.flag.ImGuiWindowFlags;
79
import imgui.type.ImBoolean;
810

9-
import java.util.HashMap;
10-
import java.util.Map;
11-
1211
public class ExampleImGuiColorTextEdit {
1312
private static final TextEditor EDITOR = new TextEditor();
13+
private static final String DEMO_TEXT =
14+
"// Demo C++ Code\n" +
15+
"\n" +
16+
"#include <iostream>\n" +
17+
"#include <random>\n" +
18+
"#include <vector>\n" +
19+
"\n" +
20+
"int main(int, char**) {\n" +
21+
" std::random_device rd;\n" +
22+
" std::mt19937 gen(rd());\n" +
23+
" std::uniform_int_distribution<> distrib(0, 1000);\n" +
24+
" std::vector<int> numbers;\n" +
25+
"\n" +
26+
" for (int i = 0; i < 100; i++) {\n" +
27+
" numbers.emplace_back(distrib(gen));\n" +
28+
" }\n" +
29+
"\n" +
30+
" for (auto n : numbers) {\n" +
31+
" std::cout << n << std::endl;\n" +
32+
" }\n" +
33+
"\n" +
34+
" return 0;\n" +
35+
"}\n";
36+
1437

1538
static {
16-
TextEditorLanguageDefinition lang = TextEditorLanguageDefinition.C();
17-
18-
String[] ppnames = {
19-
"NULL", "PM_REMOVE",
20-
"ZeroMemory", "DXGI_SWAP_EFFECT_DISCARD", "D3D_FEATURE_LEVEL", "D3D_DRIVER_TYPE_HARDWARE", "WINAPI", "D3D11_SDK_VERSION", "assert"};
21-
String[] ppvalues = {
22-
"#define NULL ((void*)0)",
23-
"#define PM_REMOVE (0x0001)",
24-
"Microsoft's own memory zapper function\n(which is a macro actually)\nvoid ZeroMemory(\n\t[in] PVOID Destination,\n\t[in] SIZE_T Length\n); ",
25-
"enum DXGI_SWAP_EFFECT::DXGI_SWAP_EFFECT_DISCARD = 0",
26-
"enum D3D_FEATURE_LEVEL",
27-
"enum D3D_DRIVER_TYPE::D3D_DRIVER_TYPE_HARDWARE = ( D3D_DRIVER_TYPE_UNKNOWN + 1 )",
28-
"#define WINAPI __stdcall",
29-
"#define D3D11_SDK_VERSION (7)",
30-
" #define assert(expression) (void)( \n" +
31-
" (!!(expression)) || \n" +
32-
" (_wassert(_CRT_WIDE(#expression), _CRT_WIDE(__FILE__), (unsigned)(__LINE__)), 0) \n" +
33-
" )"
34-
};
35-
36-
// Adding custom preproc identifiers
37-
Map<String, String> preprocIdentifierMap = new HashMap<>();
38-
for (int i = 0; i < ppnames.length; ++i) {
39-
preprocIdentifierMap.put(ppnames[i], ppvalues[i]);
40-
}
41-
lang.setPreprocIdentifiers(preprocIdentifierMap);
42-
43-
String[] identifiers = {
44-
"HWND", "HRESULT", "LPRESULT","D3D11_RENDER_TARGET_VIEW_DESC", "DXGI_SWAP_CHAIN_DESC","MSG","LRESULT","WPARAM", "LPARAM","UINT","LPVOID",
45-
"ID3D11Device", "ID3D11DeviceContext", "ID3D11Buffer", "ID3D11Buffer", "ID3D10Blob", "ID3D11VertexShader", "ID3D11InputLayout", "ID3D11Buffer",
46-
"ID3D10Blob", "ID3D11PixelShader", "ID3D11SamplerState", "ID3D11ShaderResourceView", "ID3D11RasterizerState", "ID3D11BlendState", "ID3D11DepthStencilState",
47-
"IDXGISwapChain", "ID3D11RenderTargetView", "ID3D11Texture2D", "TextEditor" };
48-
String[] idecls = {
49-
"typedef HWND_* HWND", "typedef long HRESULT", "typedef long* LPRESULT", "struct D3D11_RENDER_TARGET_VIEW_DESC", "struct DXGI_SWAP_CHAIN_DESC",
50-
"typedef tagMSG MSG\n * Message structure","typedef LONG_PTR LRESULT","WPARAM", "LPARAM","UINT","LPVOID",
51-
"ID3D11Device", "ID3D11DeviceContext", "ID3D11Buffer", "ID3D11Buffer", "ID3D10Blob", "ID3D11VertexShader", "ID3D11InputLayout", "ID3D11Buffer",
52-
"ID3D10Blob", "ID3D11PixelShader", "ID3D11SamplerState", "ID3D11ShaderResourceView", "ID3D11RasterizerState", "ID3D11BlendState", "ID3D11DepthStencilState",
53-
"IDXGISwapChain", "ID3D11RenderTargetView", "ID3D11Texture2D", "class TextEditor" };
54-
55-
// Adding custom identifiers
56-
Map<String, String> identifierMap = new HashMap<>();
57-
for (int i = 0; i < ppnames.length; ++i) {
58-
identifierMap.put(identifiers[i], idecls[i]);
59-
}
60-
lang.setIdentifiers(identifierMap);
61-
62-
EDITOR.setLanguageDefinition(lang);
63-
64-
// Adding error markers
65-
Map<Integer, String> errorMarkers = new HashMap<>();
66-
errorMarkers.put(1, "Expected '>'");
67-
EDITOR.setErrorMarkers(errorMarkers);
68-
69-
EDITOR.setTextLines(new String[]{
70-
"#include <iostream",
71-
"",
72-
"int main() {",
73-
" std::cout << \"Hello, World!\" << std::endl;",
74-
"}"
75-
});
39+
EDITOR.setText(DEMO_TEXT);
40+
EDITOR.setLanguage(TextEditorLanguage.Cpp());
41+
EDITOR.setPaletteColor(TextEditorColor.currentLineNumber, 0xFFFFC080);
42+
EDITOR.scrollToLine(9, TextEditorScroll.alignMiddle);
7643
}
7744

7845
public static void show(final ImBoolean showImColorTextEditWindow) {
79-
ImGui.setNextWindowSize(500, 400);
46+
ImGui.setNextWindowSize(500, 400, ImGuiCond.FirstUseEver);
8047
if (ImGui.begin("Text Editor", showImColorTextEditWindow,
8148
ImGuiWindowFlags.HorizontalScrollbar | ImGuiWindowFlags.MenuBar)) {
8249
if (ImGui.beginMenuBar()) {
@@ -89,52 +56,54 @@ public static void show(final ImBoolean showImColorTextEditWindow) {
8956
ImGui.endMenu();
9057
}
9158
if (ImGui.beginMenu("Edit")) {
92-
final boolean ro = EDITOR.isReadOnly();
59+
final boolean ro = EDITOR.isReadOnlyEnabled();
9360
if (ImGui.menuItem("Read-only mode", "", ro)) {
94-
EDITOR.setReadOnly(!ro);
61+
EDITOR.setReadOnlyEnabled(!ro);
9562
}
9663

9764
ImGui.separator();
9865

99-
if (ImGui.menuItem("Undo", "ALT-Backspace", !ro && EDITOR.canUndo())) {
100-
EDITOR.undo(1);
66+
if (ImGui.menuItem("Undo", "Ctrl-Z", !ro && EDITOR.canUndo())) {
67+
EDITOR.undo();
10168
}
10269
if (ImGui.menuItem("Redo", "Ctrl-Y", !ro && EDITOR.canRedo())) {
103-
EDITOR.redo(1);
70+
EDITOR.redo();
10471
}
10572

10673
ImGui.separator();
10774

108-
if (ImGui.menuItem("Copy", "Ctrl-C", EDITOR.hasSelection())) {
75+
if (ImGui.menuItem("Copy", "Ctrl-C", EDITOR.anyCursorHasSelection())) {
10976
EDITOR.copy();
11077
}
111-
if (ImGui.menuItem("Cut", "Ctrl-X", !ro && EDITOR.hasSelection())) {
78+
if (ImGui.menuItem("Cut", "Ctrl-X", !ro && EDITOR.anyCursorHasSelection())) {
11279
EDITOR.cut();
11380
}
114-
if (ImGui.menuItem("Delete", "Del", !ro && EDITOR.hasSelection())) {
115-
EDITOR.delete();
81+
if (ImGui.menuItem("Delete", "Del", !ro && EDITOR.anyCursorHasSelection())) {
82+
EDITOR.replaceTextInAllCursors("");
11683
}
11784
if (ImGui.menuItem("Paste", "Ctrl-V", !ro && ImGui.getClipboardText() != null)) {
11885
EDITOR.paste();
11986
}
87+
if (ImGui.menuItem("Select All", "Ctrl-A", !EDITOR.isEmpty())) {
88+
EDITOR.selectAll();
89+
}
12090

12191
ImGui.endMenu();
12292
}
12393

12494
ImGui.endMenuBar();
12595
}
12696

127-
TextEditorCoordinates cpos = EDITOR.getCursorPosition();
97+
TextEditorCursorPosition cpos = EDITOR.getMainCursorPosition();
12898

129-
String overwrite = EDITOR.isOverwrite() ? "Ovr" : "Ins";
99+
String overwrite = EDITOR.isOverwriteEnabled() ? "Ovr" : "Ins";
130100
String canUndo = EDITOR.canUndo() ? "*" : " ";
131101

132-
ImGui.text(cpos.mLine + "/" + cpos.mColumn + " " + EDITOR.getTotalLines() + " lines | " + overwrite + " | " + canUndo);
102+
ImGui.text(cpos.line + "/" + cpos.column + " " + EDITOR.getLineCount() + " lines | " + overwrite + " | " + canUndo);
133103

134104
EDITOR.render("TextEditor");
135105

136106
ImGui.end();
137107
}
138108
}
139109
}
140-
*/

example/src/main/java/Extra.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ public class Extra {
99
private static final ImBoolean SHOW_DRAG_N_DROP_WINDOW = new ImBoolean(false);
1010
private static final ImBoolean SHOW_IMPLOT_DEMO_WINDOW = new ImBoolean(false);
1111
private static final ImBoolean SHOW_IMGUIZMO_DEMO = new ImBoolean(false);
12-
// private static final ImBoolean SHOW_IMGUI_COLOR_TEXT_EDIT_WINDOW = new ImBoolean(false);
12+
private static final ImBoolean SHOW_IMGUI_COLOR_TEXT_EDIT_WINDOW = new ImBoolean(false);
1313
// private static final ImBoolean SHOW_IMGUI_FILE_DIALOG_WINDOW = new ImBoolean(false);
1414
private static final ImBoolean SHOW_IMGUI_MEMORY_EDITOR_WINDOW = new ImBoolean(false);
1515
private static final ImBoolean SHOW_IMGUI_CANVAS_EDITOR_WINDOW = new ImBoolean(false);
@@ -26,7 +26,7 @@ public static void show(final Application app) {
2626
ImGui.checkbox("Show Drag'N'Drop Demo Window", SHOW_DRAG_N_DROP_WINDOW);
2727
ImGui.checkbox("Show ImPlot Demo Window", SHOW_IMPLOT_DEMO_WINDOW);
2828
ImGui.checkbox("Show ImGuizmo Demo Window", SHOW_IMGUIZMO_DEMO);
29-
// ImGui.checkbox("Show ImGuiColorTextEdit Demo Window", SHOW_IMGUI_COLOR_TEXT_EDIT_WINDOW);
29+
ImGui.checkbox("Show ImGuiColorTextEdit Demo Window", SHOW_IMGUI_COLOR_TEXT_EDIT_WINDOW);
3030
// ImGui.checkbox("Show ImGuiFileDialog Demo Window", SHOW_IMGUI_FILE_DIALOG_WINDOW);
3131
ImGui.checkbox("Show ImGui MemoryEditor Demo Window", SHOW_IMGUI_MEMORY_EDITOR_WINDOW);
3232
ImGui.checkbox("Show ImGui Canvas Demo Window", SHOW_IMGUI_CANVAS_EDITOR_WINDOW);
@@ -57,9 +57,9 @@ public static void show(final Application app) {
5757
ExampleImPlot.show(SHOW_IMPLOT_DEMO_WINDOW);
5858
}
5959

60-
// if (SHOW_IMGUI_COLOR_TEXT_EDIT_WINDOW.get()) {
61-
// ExampleImGuiColorTextEdit.show(SHOW_IMGUI_COLOR_TEXT_EDIT_WINDOW);
62-
// }
60+
if (SHOW_IMGUI_COLOR_TEXT_EDIT_WINDOW.get()) {
61+
ExampleImGuiColorTextEdit.show(SHOW_IMGUI_COLOR_TEXT_EDIT_WINDOW);
62+
}
6363

6464
// if (SHOW_IMGUI_FILE_DIALOG_WINDOW.get()) {
6565
// ExampleImGuiFileDialog.show(SHOW_IMGUI_FILE_DIALOG_WINDOW);

0 commit comments

Comments
 (0)