-
-
Notifications
You must be signed in to change notification settings - Fork 89
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Example] Add example of Canvas Editor (#126)
* [Example] Add example of Canvas Editor * [Example] Adjust Canvas Editor example (#126) * [Example] Wrap examples to their own window * Tweaks Co-authored-by: SpaiR <klimbetoo@gmail.com>
- Loading branch information
1 parent
5b0e867
commit 3a494ba
Showing
3 changed files
with
165 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<ImVec2> 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(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters