Files
imgui-java/imgui-lwjgl3/src/test/java/ExampleUi.java
T

513 lines
18 KiB
Java

import imgui.ImGuiViewport;
import imgui.flag.ImGuiColorEditFlags;
import imgui.flag.ImGuiCond;
import imgui.flag.ImGuiDir;
import imgui.flag.ImGuiInputTextFlags;
import imgui.flag.ImGuiStyleVar;
import imgui.flag.ImGuiWindowFlags;
import imgui.extension.imnodes.ImNodes;
import imgui.extension.imnodes.ImNodesContext;
import imgui.extension.imnodes.flag.ImNodesPinShape;
import imgui.extension.nodeditor.NodeEditor;
import imgui.internal.ImGui;
import imgui.internal.flag.ImGuiDockNodeFlags;
import imgui.extension.nodeditor.NodeEditorConfig;
import imgui.extension.nodeditor.NodeEditorContext;
import imgui.extension.nodeditor.flag.NodeEditorPinKind;
import imgui.type.ImBoolean;
import imgui.ImColor;
import imgui.type.ImInt;
import imgui.type.ImLong;
import imgui.type.ImString;
import org.lwjgl.BufferUtils;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
import static org.lwjgl.opengl.GL32.GL_CLAMP_TO_EDGE;
import static org.lwjgl.opengl.GL32.GL_LINEAR;
import static org.lwjgl.opengl.GL32.GL_RGBA;
import static org.lwjgl.opengl.GL32.GL_RGBA8;
import static org.lwjgl.opengl.GL32.GL_TEXTURE_2D;
import static org.lwjgl.opengl.GL32.GL_TEXTURE_MAG_FILTER;
import static org.lwjgl.opengl.GL32.GL_TEXTURE_MIN_FILTER;
import static org.lwjgl.opengl.GL32.GL_TEXTURE_WRAP_S;
import static org.lwjgl.opengl.GL32.GL_TEXTURE_WRAP_T;
import static org.lwjgl.opengl.GL32.GL_UNSIGNED_BYTE;
import static org.lwjgl.opengl.GL32.glBindTexture;
import static org.lwjgl.opengl.GL32.glGenTextures;
import static org.lwjgl.opengl.GL32.glTexImage2D;
import static org.lwjgl.opengl.GL32.glTexParameteri;
@SuppressWarnings({"MagicNumber", "VisibilityModifier"})
final class ExampleUi {
private static final String IMGUI_DEMO_LINK = "https://raw.githubusercontent.com/ocornut/imgui/05bc204/imgui_demo.cpp";
private static final int COLOR_DODGERBLUE = ImColor.rgbToColor("#1E90FF");
private static final int COLOR_CORAL = ImColor.rgbToColor("#FF7F50");
private static final int COLOR_LIMEGREEN = ImColor.rgbToColor("#32CD32");
// Test data for payload
private String dropTargetText = "Drop Here";
// Resizable input example
private final ImString resizableStr = new ImString(5);
// Toggles
private final ImBoolean showBottomDockedWindow = new ImBoolean(true);
private final ImBoolean showDemoWindow = new ImBoolean();
private final ImBoolean showImNodesWindow = new ImBoolean(false);
private final ImBoolean showImNodeEditorWindow = new ImBoolean(false);
// Attach image example
private int dukeTexture = 0;
private boolean isBottomDockedWindowInit = false;
// To modify background color dynamically
final float[] backgroundColor = new float[]{0.5f, 0, 0};
// Context for imnodes example
private ImNodesContext imNodesContext;
// Context for imgui-node-editor example
private NodeEditorContext nodeEditorContext;
// Graph used both for imnodes and imgui-node-editor demo
private final Graph graph = new Graph();
void render() throws Exception {
if (imNodesContext == null) {
imNodesContext = new ImNodesContext();
}
if (nodeEditorContext == null) {
final NodeEditorConfig config = new NodeEditorConfig();
config.setSettingsFile(null);
nodeEditorContext = new NodeEditorContext(config);
}
final int dockspaceId = ImGui.getID("MyDockSpace");
showDockSpace(dockspaceId);
setupBottomDockedWindow(dockspaceId);
showBottomDockedWindow();
final ImGuiViewport mainViewport = ImGui.getMainViewport();
ImGui.setNextWindowSize(600, 300, ImGuiCond.Once);
ImGui.setNextWindowPos(mainViewport.getWorkPosX() + 10, mainViewport.getWorkPosY() + 10, ImGuiCond.Once);
ImGui.begin("Custom window"); // Start Custom window
showWindowImage();
showToggles();
ImGui.separator();
showDragNDrop();
showBackgroundPicker();
ImGui.separator();
showResizableInput();
ImGui.separator();
ImGui.newLine();
showDemoLink();
ImGui.end(); // End Custom window
if (showDemoWindow.get()) {
ImGui.showDemoWindow(showDemoWindow);
}
if (showImNodesWindow.get()) {
showImNodesWindow();
}
if (showImNodeEditorWindow.get()) {
showImNodeEditorWindow();
}
}
private void showDockSpace(final int dockspaceId) {
final ImGuiViewport mainViewport = ImGui.getMainViewport();
final int windowFlags = ImGuiWindowFlags.NoTitleBar | ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.NoResize
| ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoBringToFrontOnFocus | ImGuiWindowFlags.NoNavFocus | ImGuiWindowFlags.NoBackground;
ImGui.setNextWindowPos(mainViewport.getWorkPosX(), mainViewport.getWorkPosY());
ImGui.setNextWindowSize(mainViewport.getWorkSizeX(), mainViewport.getWorkSizeY());
ImGui.setNextWindowViewport(mainViewport.getID());
ImGui.pushStyleVar(ImGuiStyleVar.WindowRounding, 0);
ImGui.pushStyleVar(ImGuiStyleVar.WindowBorderSize, 0);
ImGui.pushStyleVar(ImGuiStyleVar.WindowPadding, 0, 0);
ImGui.begin("Dockspace Demo", windowFlags);
ImGui.popStyleVar(3);
ImGui.dockSpace(dockspaceId, 0, 0, ImGuiDockNodeFlags.PassthruCentralNode);
ImGui.end();
}
private void setupBottomDockedWindow(final int dockspaceId) {
if (!isBottomDockedWindowInit) {
ImGui.dockBuilderRemoveNode(dockspaceId);
ImGui.dockBuilderAddNode(dockspaceId, ImGuiDockNodeFlags.DockSpace);
final int dockIdBottom = ImGui.dockBuilderSplitNode(dockspaceId, ImGuiDir.Down, .25f, null, null);
ImGui.dockBuilderDockWindow("Bottom Docked Window", dockIdBottom);
ImGui.dockBuilderSetNodeSize(dockIdBottom, 150f, 150f);
ImGui.dockBuilderFinish(dockspaceId);
isBottomDockedWindowInit = true;
}
}
private void showBottomDockedWindow() {
if (showBottomDockedWindow.get()) {
ImGui.begin("Bottom Docked Window", showBottomDockedWindow, ImGuiWindowFlags.AlwaysAutoResize);
ImGui.text("An example of how to create docked windows.");
ImGui.end();
}
}
private void showWindowImage() throws IOException {
if (dukeTexture == 0) {
dukeTexture = loadTexture(ImageIO.read(new File("src/test/resources/Duke_waving.png")));
}
// Draw an image in the bottom-right corner of the window
final float xPoint = ImGui.getWindowPosX() + ImGui.getWindowSizeX() - 100;
final float yPoint = ImGui.getWindowPosY() + ImGui.getWindowSizeY();
ImGui.getWindowDrawList().addImage(dukeTexture, xPoint, yPoint - 180, xPoint + 100, yPoint);
}
private void showToggles() {
ImGui.checkbox("Show Demo Window", showDemoWindow);
ImGui.checkbox("Show Bottom Docked Window", showBottomDockedWindow);
ImGui.checkbox("Show demo for imnodes", showImNodesWindow);
ImGui.checkbox("Show demo for imgui-node-editor", showImNodeEditorWindow);
if (ImGui.button("Reset Bottom Dock Window")) {
isBottomDockedWindowInit = false;
}
}
private void showDragNDrop() {
ImGui.button("Drag me");
if (ImGui.beginDragDropSource()) {
ImGui.setDragDropPayloadObject("payload_type", "Test Payload");
ImGui.text("Drag started");
ImGui.endDragDropSource();
}
ImGui.sameLine();
ImGui.text(dropTargetText);
if (ImGui.beginDragDropTarget()) {
final Object payload = ImGui.acceptDragDropPayloadObject("payload_type");
if (payload != null) {
dropTargetText = (String) payload;
}
ImGui.endDragDropTarget();
}
}
private void showBackgroundPicker() {
ImGui.alignTextToFramePadding();
ImGui.text("Background color:");
ImGui.sameLine();
ImGui.colorEdit3("##click_counter_col", backgroundColor, ImGuiColorEditFlags.NoInputs | ImGuiColorEditFlags.NoDragDrop);
}
private void showResizableInput() {
ImGui.text("You can use text inputs with auto-resizable strings!");
ImGui.inputText("Resizable input", resizableStr, ImGuiInputTextFlags.CallbackResize);
ImGui.text("text len:");
ImGui.sameLine();
ImGui.textColored(COLOR_DODGERBLUE, Integer.toString(resizableStr.getLength()));
ImGui.sameLine();
ImGui.text("| buffer size:");
ImGui.sameLine();
ImGui.textColored(COLOR_CORAL, Integer.toString(resizableStr.getBufferSize()));
}
private void showDemoLink() {
ImGui.text("Consider to look the original ImGui demo: ");
ImGui.setNextItemWidth(500);
ImGui.textColored(COLOR_LIMEGREEN, IMGUI_DEMO_LINK);
ImGui.sameLine();
if (ImGui.button("Copy")) {
ImGui.setClipboardText(IMGUI_DEMO_LINK);
}
}
private void showImNodesWindow() {
ImGui.setNextWindowSize(400F, 400F, ImGuiCond.Appearing);
ImGui.begin("Demo imnodes", showImNodesWindow);
ImGui.text("This a demo graph editor for ImNodes");
ImNodes.editorContextSet(imNodesContext);
ImNodes.beginNodeEditor();
for (Graph.GraphNode node : graph.nodes.values()) {
ImNodes.beginNode(node.nodeId);
ImNodes.beginNodeTitleBar();
ImGui.text(node.getName());
ImNodes.endNodeTitleBar();
ImNodes.beginInputAttribute(node.getInputPinId(), ImNodesPinShape.CircleFilled);
ImGui.text("In");
ImNodes.endInputAttribute();
ImGui.sameLine();
ImNodes.beginOutputAttribute(node.getOutputPinId());
ImGui.text("Out");
ImNodes.endOutputAttribute();
ImNodes.endNode();
}
int uniqueLinkId = 1;
for (Graph.GraphNode node : graph.nodes.values()) {
if (graph.nodes.containsKey(node.outputNodeId)) {
ImNodes.link(uniqueLinkId++, node.getOutputPinId(), graph.nodes.get(node.outputNodeId).getInputPinId());
}
}
final boolean isEditorHovered = ImNodes.isEditorHovered();
ImNodes.endNodeEditor();
final ImInt a = new ImInt();
final ImInt b = new ImInt();
if (ImNodes.isLinkCreated(a, b)) {
final Graph.GraphNode source = graph.findByOutput(a.get());
final Graph.GraphNode target = graph.findByInput(b.get());
if (source != null && target != null && source.outputNodeId != target.nodeId) {
source.outputNodeId = target.nodeId;
}
}
if (ImGui.isMouseClicked(1)) {
final int hoveredNode = ImNodes.getHoveredNode();
if (hoveredNode != -1) {
ImGui.openPopup("node-context");
ImGui.getStateStorage().setInt(ImGui.getID("delete-node-id"), hoveredNode);
} else if (isEditorHovered) {
ImGui.openPopup("node-editor-context");
}
}
if (ImGui.isPopupOpen("node-context")) {
final int targetNode = ImGui.getStateStorage().getInt(ImGui.getID("delete-node-id"));
if (ImGui.beginPopup("node-context")) {
if (ImGui.button("Delete " + graph.nodes.get(targetNode).getName())) {
graph.nodes.remove(targetNode);
ImGui.closeCurrentPopup();
}
ImGui.endPopup();
}
}
if (ImGui.beginPopup("node-editor-context")) {
if (ImGui.button("Create new node")) {
final Graph.GraphNode node = graph.createGraphNode();
ImNodes.setNodeScreenSpacePos(node.nodeId, ImGui.getMousePosX(), ImGui.getMousePosY());
ImGui.closeCurrentPopup();
}
ImGui.endPopup();
}
ImGui.end();
}
private void showImNodeEditorWindow() {
ImGui.setNextWindowSize(400F, 400F, ImGuiCond.Appearing);
ImGui.begin("Demo imgui-node-editor", showImNodeEditorWindow);
ImGui.text("This a demo graph editor for imgui-node-editor");
if (ImGui.button("Navigate to content")) {
NodeEditor.navigateToContent(1F);
}
NodeEditor.setCurrentEditor(nodeEditorContext);
NodeEditor.begin("Node Editor");
for (Graph.GraphNode node : graph.nodes.values()) {
NodeEditor.beginNode(node.nodeId);
ImGui.text(node.getName());
NodeEditor.beginPin(node.getInputPinId(), NodeEditorPinKind.Input);
ImGui.text("-> In");
NodeEditor.endPin();
ImGui.sameLine();
NodeEditor.beginPin(node.getOutputPinId(), NodeEditorPinKind.Output);
ImGui.text("Out ->");
NodeEditor.endPin();
NodeEditor.endNode();
}
if (NodeEditor.beginCreate()) {
final ImLong a = new ImLong();
final ImLong b = new ImLong();
if (NodeEditor.queryNewLink(a, b)) {
final Graph.GraphNode source = graph.findByOutput(a.get());
final Graph.GraphNode target = graph.findByInput(b.get());
if (source != null && target != null && source.outputNodeId != target.nodeId && NodeEditor.acceptNewItem()) {
source.outputNodeId = target.nodeId;
}
}
}
NodeEditor.endCreate();
int uniqueLinkId = 1;
for (Graph.GraphNode node : graph.nodes.values()) {
if (graph.nodes.containsKey(node.outputNodeId)) {
NodeEditor.link(uniqueLinkId++, node.getOutputPinId(), graph.nodes.get(node.outputNodeId).getInputPinId());
}
}
NodeEditor.suspend();
final long nodeWithContextMenu = NodeEditor.getNodeWithContextMenu();
if (nodeWithContextMenu != -1) {
ImGui.openPopup("node-context");
ImGui.getStateStorage().setInt(ImGui.getID("delete-node-id"), (int) nodeWithContextMenu);
}
if (ImGui.isPopupOpen("node-context")) {
final int targetNode = ImGui.getStateStorage().getInt(ImGui.getID("delete-node-id"));
if (ImGui.beginPopup("node-context")) {
if (ImGui.button("Delete " + graph.nodes.get(targetNode).getName())) {
graph.nodes.remove(targetNode);
ImGui.closeCurrentPopup();
}
ImGui.endPopup();
}
}
if (NodeEditor.showBackgroundContextMenu()) {
ImGui.openPopup("node-editor-context");
}
if (ImGui.beginPopup("node-editor-context")) {
if (ImGui.button("Create new node")) {
final Graph.GraphNode node = graph.createGraphNode();
final float canvasX = NodeEditor.toCanvasX(ImGui.getMousePosX());
final float canvasY = NodeEditor.toCanvasY(ImGui.getMousePosY());
NodeEditor.setNodePosition(node.nodeId, canvasX, canvasY);
ImGui.closeCurrentPopup();
}
ImGui.endPopup();
}
NodeEditor.resume();
NodeEditor.end();
ImGui.end();
}
private int loadTexture(final BufferedImage image) {
final int[] pixels = new int[image.getWidth() * image.getHeight()];
image.getRGB(0, 0, image.getWidth(), image.getHeight(), pixels, 0, image.getWidth());
final ByteBuffer buffer = BufferUtils.createByteBuffer(image.getWidth() * image.getHeight() * 4); // 4 for RGBA, 3 for RGB
for (int y = 0; y < image.getHeight(); y++) {
for (int x = 0; x < image.getWidth(); x++) {
final int pixel = pixels[y * image.getWidth() + x];
buffer.put((byte) ((pixel >> 16) & 0xFF));
buffer.put((byte) ((pixel >> 8) & 0xFF));
buffer.put((byte) (pixel & 0xFF));
buffer.put((byte) ((pixel >> 24) & 0xFF));
}
}
buffer.flip();
final int textureID = glGenTextures();
glBindTexture(GL_TEXTURE_2D, textureID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, image.getWidth(), image.getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
return textureID;
}
// Simple graph struct for both of node editors demos
private static final class Graph {
private int nextNodeId = 1;
private int nextPinId = 100;
final Map<Integer, GraphNode> nodes = new HashMap<>();
private Graph() {
final GraphNode first = createGraphNode();
final GraphNode second = createGraphNode();
first.outputNodeId = second.nodeId;
}
public GraphNode createGraphNode() {
final GraphNode node = new GraphNode(nextNodeId++, nextPinId++, nextPinId++);
this.nodes.put(node.nodeId, node);
return node;
}
public GraphNode findByInput(final long inputPinId) {
for (GraphNode node : nodes.values()) {
if (node.getInputPinId() == inputPinId) {
return node;
}
}
return null;
}
public GraphNode findByOutput(final long outputPinId) {
for (GraphNode node : nodes.values()) {
if (node.getOutputPinId() == outputPinId) {
return node;
}
}
return null;
}
private static final class GraphNode {
private final int nodeId;
private final int inputPinId;
private final int outputPinId;
public int outputNodeId = -1;
private GraphNode(final int nodeId, final int inputPinId, final int outputPintId) {
this.nodeId = nodeId;
this.inputPinId = inputPinId;
this.outputPinId = outputPintId;
}
public int getInputPinId() {
return inputPinId;
}
public int getOutputPinId() {
return outputPinId;
}
public String getName() {
return "Node " + (char) (64 + nodeId);
}
}
}
}