mirror of
https://github.com/ocornut/imgui.git
synced 2024-11-27 16:29:02 +08:00
Demo: Improve "Custom Rendering"->"Canvas" demo with a grid, scrolling and context menu.
This commit is contained in:
parent
4929a8e4a5
commit
912c45ab23
@ -68,6 +68,8 @@ Other Changes:
|
||||
by modifying the 'style.CircleSegmentMaxError' value. [@ShironekoBen]
|
||||
- ImDrawList: Fixed minor bug introduced in 1.75 where AddCircle() with 12 segments would generate
|
||||
an extra vertex. (This bug was mistakenly marked as fixed in earlier 1.77 release). [@ShironekoBen]
|
||||
- Demo: Improve "Custom Rendering"->"Canvas" demo with a grid, scrolling and context menu.
|
||||
Also showcase using InvisibleButton() will multiple mouse buttons flags.
|
||||
- Demo: Tweak "Child Windows" section.
|
||||
- Style Editor: Added preview of circle auto-tessellation when editing the corresponding value.
|
||||
- Backends: OpenGL3: Added support for glad2 loader. (#3330) [@moritz-h]
|
||||
|
119
imgui_demo.cpp
119
imgui_demo.cpp
@ -4859,13 +4859,13 @@ static void ShowExampleAppCustomRendering(bool* p_open)
|
||||
// overloaded operators, etc. Define IM_VEC2_CLASS_EXTRA in imconfig.h to create implicit conversions between your
|
||||
// types and ImVec2/ImVec4. Dear ImGui defines overloaded operators but they are internal to imgui.cpp and not
|
||||
// exposed outside (to avoid messing with your types) In this example we are not using the maths operators!
|
||||
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
||||
|
||||
if (ImGui::BeginTabBar("##TabBar"))
|
||||
{
|
||||
if (ImGui::BeginTabItem("Primitives"))
|
||||
{
|
||||
ImGui::PushItemWidth(-ImGui::GetFontSize() * 10);
|
||||
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
||||
|
||||
// Draw gradients
|
||||
// (note that those are currently exacerbating our sRGB/Linear issues)
|
||||
@ -4949,56 +4949,95 @@ static void ShowExampleAppCustomRendering(bool* p_open)
|
||||
|
||||
if (ImGui::BeginTabItem("Canvas"))
|
||||
{
|
||||
static ImVector<ImVec2> points;
|
||||
struct ItemLine { ImVec2 p0, p1; ItemLine(const ImVec2& _p0, const ImVec2& _p1) { p0 = _p0; p1 = _p1; } };
|
||||
static ImVector<ItemLine> lines;
|
||||
static ImVec2 scrolling(0.0f, 0.0f);
|
||||
static bool show_grid = true;
|
||||
static bool adding_line = false;
|
||||
if (ImGui::Button("Clear")) points.clear();
|
||||
if (points.Size >= 2) { ImGui::SameLine(); if (ImGui::Button("Undo")) { points.pop_back(); points.pop_back(); } }
|
||||
ImGui::Text("Left-click and drag to add lines,\nRight-click to undo");
|
||||
|
||||
// Here we are using InvisibleButton() as a convenience to 1) advance the cursor and 2) allows us to use
|
||||
// IsItemHovered(). But you can also draw directly and poll mouse/keyboard by yourself.
|
||||
// You can manipulate the cursor using GetCursorPos() and SetCursorPos().
|
||||
// If you only use the ImDrawList API, you can notify the owner window of its extends with SetCursorPos(max).
|
||||
ImVec2 canvas_p = ImGui::GetCursorScreenPos(); // ImDrawList API uses screen coordinates!
|
||||
ImGui::Checkbox("Show grid", &show_grid);
|
||||
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, ImVec2(0, 0)); // Disable padding
|
||||
// ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(50, 50, 50, 255)); // Set a background color
|
||||
// ImGui::BeginChild("canvas", 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 canvas_p0 = ImGui::GetCursorScreenPos(); // ImDrawList API uses screen coordinates!
|
||||
ImVec2 canvas_sz = ImGui::GetContentRegionAvail(); // Resize canvas to what's available
|
||||
if (canvas_sz.x < 50.0f) canvas_sz.x = 50.0f;
|
||||
if (canvas_sz.y < 50.0f) canvas_sz.y = 50.0f;
|
||||
draw_list->AddRectFilledMultiColor(canvas_p, ImVec2(canvas_p.x + canvas_sz.x, canvas_p.y + canvas_sz.y), IM_COL32(50, 50, 50, 255), IM_COL32(50, 50, 60, 255), IM_COL32(60, 60, 70, 255), IM_COL32(50, 50, 60, 255));
|
||||
draw_list->AddRect(canvas_p, ImVec2(canvas_p.x + canvas_sz.x, canvas_p.y + canvas_sz.y), IM_COL32(255, 255, 255, 255));
|
||||
ImVec2 canvas_p1 = ImVec2(canvas_p0.x + canvas_sz.x, canvas_p0.y + canvas_sz.y);
|
||||
|
||||
bool adding_preview = false;
|
||||
ImGui::InvisibleButton("canvas", canvas_sz);
|
||||
ImVec2 mouse_pos_global = ImGui::GetIO().MousePos;
|
||||
ImVec2 mouse_pos_canvas = ImVec2(mouse_pos_global.x - canvas_p.x, mouse_pos_global.y - canvas_p.y);
|
||||
// Draw border and background color
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
||||
draw_list->AddRectFilled(canvas_p0, canvas_p1, IM_COL32(50, 50, 50, 255));
|
||||
draw_list->AddRect(canvas_p0, canvas_p1, IM_COL32(255, 255, 255, 255));
|
||||
|
||||
// This will catch our interactions
|
||||
ImGui::InvisibleButton("canvas", canvas_sz, ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight);
|
||||
const bool is_hovered = ImGui::IsItemHovered(); // Hovered
|
||||
const bool is_active = ImGui::IsItemActive(); // Held
|
||||
const ImVec2 origin(canvas_p0.x + scrolling.x, canvas_p0.y + scrolling.y); // Lock scrolled origin
|
||||
const ImVec2 mouse_pos_in_canvas(io.MousePos.x - origin.x, io.MousePos.y - origin.y);
|
||||
|
||||
// Add first and second point
|
||||
if (is_hovered && !adding_line && ImGui::IsMouseClicked(ImGuiMouseButton_Left))
|
||||
{
|
||||
lines.push_back(ItemLine(mouse_pos_in_canvas, mouse_pos_in_canvas));
|
||||
adding_line = true;
|
||||
}
|
||||
if (adding_line)
|
||||
{
|
||||
adding_preview = true;
|
||||
points.push_back(mouse_pos_canvas);
|
||||
if (!ImGui::IsMouseDown(0))
|
||||
adding_line = adding_preview = false;
|
||||
}
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
if (!adding_line && ImGui::IsMouseClicked(0))
|
||||
{
|
||||
points.push_back(mouse_pos_canvas);
|
||||
adding_line = true;
|
||||
}
|
||||
if (ImGui::IsMouseClicked(1) && !points.empty())
|
||||
{
|
||||
adding_line = adding_preview = false;
|
||||
points.pop_back();
|
||||
points.pop_back();
|
||||
}
|
||||
lines.back().p1 = mouse_pos_in_canvas;
|
||||
if (!ImGui::IsMouseDown(ImGuiMouseButton_Left))
|
||||
adding_line = false;
|
||||
}
|
||||
|
||||
// Draw all lines in the canvas (with a clipping rectangle so they don't stray out of it).
|
||||
draw_list->PushClipRect(canvas_p, ImVec2(canvas_p.x + canvas_sz.x, canvas_p.y + canvas_sz.y), true);
|
||||
for (int i = 0; i < points.Size - 1; i += 2)
|
||||
draw_list->AddLine(ImVec2(canvas_p.x + points[i].x, canvas_p.y + points[i].y), ImVec2(canvas_p.x + points[i + 1].x, canvas_p.y + points[i + 1].y), IM_COL32(255, 255, 0, 255), 2.0f);
|
||||
// Pan (using zero mouse threshold)
|
||||
if (is_active && ImGui::IsMouseDragging(ImGuiMouseButton_Right, 0.0f))
|
||||
{
|
||||
scrolling.x += io.MouseDelta.x;
|
||||
scrolling.y += io.MouseDelta.y;
|
||||
}
|
||||
|
||||
// Context menu (under default mouse threshold)
|
||||
// We intentionally use the same button to demonstrate using mouse drag threshold. Some may feel panning should rely on same threshold.
|
||||
ImVec2 drag_delta = ImGui::GetMouseDragDelta(ImGuiMouseButton_Right);
|
||||
if (drag_delta.x == 0.0f && drag_delta.y == 0.0f)
|
||||
ImGui::OpenPopupContextItem("context");
|
||||
if (ImGui::BeginPopup("context"))
|
||||
{
|
||||
if (adding_line)
|
||||
lines.pop_back();
|
||||
adding_line = false;
|
||||
if (ImGui::MenuItem("Remove one", NULL, false, lines.Size > 0)) { lines.pop_back(); }
|
||||
if (ImGui::MenuItem("Remove all", NULL, false, lines.Size > 0)) { lines.clear(); }
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
// Draw grid + all lines in the canvas
|
||||
draw_list->PushClipRect(canvas_p0, canvas_p1, true);
|
||||
if (show_grid)
|
||||
{
|
||||
const float GRID_STEP = 64.0f;
|
||||
for (float x = fmodf(scrolling.x, GRID_STEP); x < canvas_sz.x; x += GRID_STEP)
|
||||
draw_list->AddLine(ImVec2(canvas_p0.x + x, canvas_p0.y), ImVec2(canvas_p0.x + x, canvas_p1.y), IM_COL32(200, 200, 200, 40));
|
||||
for (float y = fmodf(scrolling.y, GRID_STEP); y < canvas_sz.y; y += GRID_STEP)
|
||||
draw_list->AddLine(ImVec2(canvas_p0.x, canvas_p0.y + y), ImVec2(canvas_p1.x, canvas_p0.y + y), IM_COL32(200, 200, 200, 40));
|
||||
}
|
||||
for (int n = 0; n < lines.Size; n++)
|
||||
draw_list->AddLine(ImVec2(origin.x + lines[n].p0.x, origin.y + lines[n].p0.y), ImVec2(origin.x + lines[n].p1.x, origin.y + lines[n].p1.y), IM_COL32(255, 255, 0, 255), 2.0f);
|
||||
draw_list->PopClipRect();
|
||||
if (adding_preview)
|
||||
points.pop_back();
|
||||
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user