diff --git a/example/src/main/java/ExampleCanvasEditor.java b/example/src/main/java/ExampleCanvasEditor.java new file mode 100644 index 0000000..8d52a15 --- /dev/null +++ b/example/src/main/java/ExampleCanvasEditor.java @@ -0,0 +1,144 @@ +import imgui.*; +import imgui.flag.ImGuiButtonFlags; +import imgui.flag.ImGuiCond; +import imgui.flag.ImGuiMouseButton; +import imgui.flag.ImGuiPopupFlags; +import imgui.type.ImBoolean; + +import java.util.ArrayList; +import java.util.List; + +public class ExampleCanvasEditor { + private static final List pointList = new ArrayList<>(); + private static final ImVec2 scrolling = new ImVec2(); + + private static boolean addingLine = false; + public static float thickness = 2.0f; + + /** + * Computes the floating-point remainder of a / b. + * + * @param a float + * @param b float + * @return computed floating-point remainder of a / b + */ + private static float fmodf(float a, float b) { + int result = (int) Math.floor(a / b); + return a - result * b; + } + + public static void show(final ImBoolean showCanvaWindow) { + ImGui.setNextWindowSize(700, 400, ImGuiCond.Once); + ImGui.setNextWindowPos(ImGui.getMainViewport().getPosX() + 200, ImGui.getMainViewport().getPosY() + 200, ImGuiCond.Once); + + if (ImGui.begin("Canvas Demo Window", showCanvaWindow)) { + ImGui.text("This a demo for ImGui Canvas editor"); + ImGui.sameLine(); + ImGui.text("Mouse Left: drag to add lines,\nMouse Right: drag to scroll, click for context menu."); + + // Typically, you would use a BeginChild()/EndChild() pair to benefit from a clipping region + own scrolling. + // Here we demonstrate that this can be replaced by simple offsetting + custom drawing + PushClipRect/PopClipRect() calls. + // To use a child window instead we could use, e.g: + // ImGui.pushStyleVar(ImGuiStyleVar.WindowPadding, 0, 0); // Disable padding + // ImGui.pushStyleColor(ImGuiCol.ChildBg, ImColor.intToColor(50, 50, 50, 255)); // Set a background color + // ImGui.beginChild("canvas", new ImVec2(0.0f, 0.0f), true, ImGuiWindowFlags.NoMove); + // ImGui.popStyleColor(); + // ImGui.popStyleVar(); + // [...] + // ImGui.endChild(); + + // Using InvisibleButton() as a convenience 1) it will advance the layout cursor and 2) allows us to use IsItemHovered()/IsItemActive() + ImVec2 canvasP0 = ImGui.getCursorScreenPos(); // ImDrawList API uses screen coordinates! + ImVec2 canvasSize = ImGui.getContentRegionAvail(); // Resize canvas to what's available + + if (canvasSize.x < 50.0f) { + canvasSize.x = 50.0f; + } + + if (canvasSize.y < 50.0f) { + canvasSize.y = 50.0f; + } + + ImVec2 canvasP1 = new ImVec2(canvasP0.x + canvasSize.x, canvasP0.y + canvasSize.y); + + // Draw border and background color + ImGuiIO io = ImGui.getIO(); + ImDrawList drawList = ImGui.getWindowDrawList(); + drawList.addRectFilled(canvasP0.x, canvasP0.y, canvasP1.x, canvasP1.y, + ImColor.intToColor(50, 50, 50, 255)); + drawList.addRect(canvasP0.x, canvasP0.y, canvasP1.x, canvasP1.y, + ImColor.intToColor(255, 255, 255, 255)); + + // This will catch our interactions + ImGui.invisibleButton("canvas", canvasSize.x, canvasSize.y, + ImGuiButtonFlags.MouseButtonLeft | ImGuiButtonFlags.MouseButtonRight); + + boolean isHovered = ImGui.isItemHovered(); // Hovered + boolean isActive = ImGui.isItemActive(); // Held + + ImVec2 origin = new ImVec2(canvasP0.x + scrolling.x, canvasP0.y + scrolling.y); // Lock scrolled origin + + ImVec2 mousePosInCanvas = new ImVec2(io.getMousePos().x - origin.x, io.getMousePos().y - origin.y); + + // Add first and second point + if (isHovered && !addingLine && ImGui.isMouseClicked(ImGuiMouseButton.Left)) { + pointList.add(mousePosInCanvas); + pointList.add(mousePosInCanvas); + addingLine = true; + } + if (addingLine) { + pointList.set(pointList.size() - 1, mousePosInCanvas); + if (!ImGui.isMouseDown(ImGuiMouseButton.Left)) { + addingLine = false; + } + } + + // Pan (we use a zero mouse threshold when there's no context menu) + // You may decide to make that threshold dynamic based on whether the mouse is hovering something etc. + float mouseThresholdForPan = -1.0f; + if (isActive && ImGui.isMouseDragging(ImGuiMouseButton.Right, mouseThresholdForPan)) { + scrolling.x += io.getMouseDelta().x; + scrolling.y += io.getMouseDelta().y; + } + + // Context menu (under default mouse threshold) + ImVec2 dragDelta = ImGui.getMouseDragDelta(ImGuiMouseButton.Right); + if (dragDelta.x == 0.0f && dragDelta.y == 0.0f) { + ImGui.openPopupOnItemClick("context", ImGuiPopupFlags.MouseButtonRight); + } + + // Draw grid + all lines in the canvas + drawList.pushClipRect(canvasP0.x, canvasP0.y, canvasP1.x, canvasP1.y, false); + float GRID_STEP = 64.0f; + for (float x = fmodf(scrolling.x, GRID_STEP); x < canvasSize.x; x += GRID_STEP) { + drawList.addLine(canvasP0.x + x, canvasP0.y, canvasP0.x + x, canvasP1.y, + ImColor.intToColor(200, 200, 200, 40)); + } + for (float y = fmodf(scrolling.y, GRID_STEP); y < canvasSize.y; y += GRID_STEP) { + drawList.addLine(canvasP0.x, canvasP0.y + y, canvasP1.x, canvasP0.y + y, + ImColor.intToColor(200, 200, 200, 40)); + } + for (int n = 0; n < pointList.size(); n += 2) { + drawList.addLine(origin.x + pointList.get(n).x, origin.y + pointList.get(n).y, + origin.x + pointList.get(n + 1).x, origin.y + pointList.get(n + 1).y, + ImColor.intToColor(255, 255, 0, 255), thickness); + } + drawList.popClipRect(); + + // Menu properties + if (ImGui.beginPopup("context")) { + addingLine = false; + if (ImGui.menuItem("Remove one", "", false, pointList.size() > 0)) { + pointList.remove(pointList.size() - 1); + pointList.remove(pointList.size() - 1); + } + if (ImGui.menuItem("Remove all", "", false, pointList.size() > 0)) { + pointList.clear(); + } + ImGui.endPopup(); + } + } + + ImGui.end(); + } +} diff --git a/example/src/main/java/Extra.java b/example/src/main/java/Extra.java index 03d5c39..bc9ce4c 100644 --- a/example/src/main/java/Extra.java +++ b/example/src/main/java/Extra.java @@ -12,6 +12,7 @@ public class Extra { private static final ImBoolean SHOW_IMGUI_COLOR_TEXT_EDIT_WINDOW = new ImBoolean(false); 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 Graph GRAPH = new Graph(); @@ -26,6 +27,7 @@ public class Extra { ImGui.checkbox("Show ImGuiColorTextEdit Demo Window", SHOW_IMGUI_COLOR_TEXT_EDIT_WINDOW); 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); if (SHOW_DEMO_WINDOW.get()) { ImGui.showDemoWindow(SHOW_DEMO_WINDOW); @@ -62,5 +64,9 @@ public class Extra { if (SHOW_IMGUI_MEMORY_EDITOR_WINDOW.get()) { ExampleImGuiMemoryEditor.show(SHOW_IMGUI_MEMORY_EDITOR_WINDOW); } + + if (SHOW_IMGUI_CANVAS_EDITOR_WINDOW.get()) { + ExampleCanvasEditor.show(SHOW_IMGUI_CANVAS_EDITOR_WINDOW); + } } } diff --git a/example/src/main/java/Main.java b/example/src/main/java/Main.java index bc45292..907f7dd 100644 --- a/example/src/main/java/Main.java +++ b/example/src/main/java/Main.java @@ -6,6 +6,7 @@ import imgui.app.Application; import imgui.app.Configuration; import imgui.flag.ImGuiConfigFlags; import imgui.flag.ImGuiInputTextFlags; +import imgui.flag.ImGuiWindowFlags; import imgui.type.ImString; import java.io.IOException; @@ -70,18 +71,21 @@ public class Main extends Application { @Override public void process() { - ImGui.text("Hello, World! " + FontAwesomeIcons.Smile); - if (ImGui.button(FontAwesomeIcons.Save + " Save")) { - count++; + if (ImGui.begin("Demo", ImGuiWindowFlags.AlwaysAutoResize)) { + ImGui.text("Hello, World! " + FontAwesomeIcons.Smile); + if (ImGui.button(FontAwesomeIcons.Save + " Save")) { + count++; + } + ImGui.sameLine(); + ImGui.text(String.valueOf(count)); + ImGui.inputText("string", str, ImGuiInputTextFlags.CallbackResize); + ImGui.text("Result: " + str.get()); + ImGui.sliderFloat("float", flt, 0, 1); + ImGui.separator(); + ImGui.text("Extra"); + Extra.show(this); } - ImGui.sameLine(); - ImGui.text(String.valueOf(count)); - ImGui.inputText("string", str, ImGuiInputTextFlags.CallbackResize); - ImGui.text("Result: " + str.get()); - ImGui.sliderFloat("float", flt, 0, 1); - ImGui.separator(); - ImGui.text("Extra"); - Extra.show(this); + ImGui.end(); } private static byte[] loadFromResources(String name) {