-
-
Notifications
You must be signed in to change notification settings - Fork 132
Expand file tree
/
Copy pathExampleCanvasEditor.java
More file actions
144 lines (122 loc) · 6.48 KB
/
ExampleCanvasEditor.java
File metadata and controls
144 lines (122 loc) · 6.48 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
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.rgba(50, 50, 50, 255));
drawList.addRect(canvasP0.x, canvasP0.y, canvasP1.x, canvasP1.y,
ImColor.rgba(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.rgba(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.rgba(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.rgba(255, 255, 0, 255), thickness);
}
drawList.popClipRect();
// Menu properties
if (ImGui.beginPopup("context")) {
addingLine = false;
if (ImGui.menuItem("Remove one", "", false, !pointList.isEmpty())) {
pointList.remove(pointList.size() - 1);
pointList.remove(pointList.size() - 1);
}
if (ImGui.menuItem("Remove all", "", false, !pointList.isEmpty())) {
pointList.clear();
}
ImGui.endPopup();
}
}
ImGui.end();
}
}