48void DrawArrow(ImDrawList* draw_list, ImVec2 a, ImVec2 b, ImU32 color,
50 const float dx = b.x - a.x;
51 const float dy = b.y - a.y;
52 const float len = std::sqrt(dx * dx + dy * dy);
55 const float ux = dx / len;
56 const float uy = dy / len;
57 const float head = std::max(5.0f, 6.0f * scale);
58 draw_list->AddLine(a, b, color, std::max(2.0f, 2.0f * scale));
59 draw_list->AddTriangleFilled(b,
60 ImVec2(b.x - ux * head - uy * head * 0.6f,
61 b.y - uy * head + ux * head * 0.6f),
62 ImVec2(b.x - ux * head + uy * head * 0.6f,
63 b.y - uy * head - ux * head * 0.6f),
70 if (overlay.
steps.empty())
72 ImGui::PushID(overlay.
title.c_str());
73 const ImGuiID key = ImGui::GetID(
"ProposalSelectedStep");
74 ImGuiStorage* storage = ImGui::GetStateStorage();
75 int selected = storage->GetInt(key, -1);
76 if (selected < -1 ||
static_cast<size_t>(selected) >= overlay.
steps.size())
78 ImGui::SetNextItemWidth(260.0f);
80 selected < 0 ? tr(
"All steps") : overlay.
steps[selected].label.c_str();
81 if (ImGui::BeginCombo(tr(
"Preview step"), label)) {
82 if (ImGui::Selectable(tr(
"All steps"), selected < 0))
84 for (
size_t i = 0; i < overlay.
steps.size(); ++i) {
85 const auto& step = overlay.
steps[i];
86 ImGui::PushID(step.id.c_str());
87 if (ImGui::Selectable(step.label.c_str(),
88 selected ==
static_cast<int>(i)))
89 selected =
static_cast<int>(i);
95 ImGui::BeginDisabled(selected <= 0);
96 if (ImGui::Button(tr(
"Previous")))
100 ImGui::BeginDisabled(selected + 1 >=
static_cast<int>(overlay.
steps.size()));
101 if (ImGui::Button(tr(
"Next")))
103 ImGui::EndDisabled();
104 storage->SetInt(key, selected);
105 if (selected >= 0 && !overlay.
steps[selected].detail.empty())
106 ImGui::TextWrapped(
"%s", overlay.
steps[selected].detail.c_str());
107 ImGui::TextDisabled(
"%s", tr(
"Preview only. Actor markers and object "
108 "footprints do not change the room."));
118 const ImU32 text = IM_COL32(255, 255, 255, 255);
119 auto to_screen = [&](
float x,
float y) {
120 return ImVec2(room_origin.x + x * scale, room_origin.y + y * scale);
122 switch (shape.
type) {
125 const ImVec2 p0 = to_screen(r.x0, r.y0);
126 const ImVec2 p1 = to_screen(r.x1, r.y1);
127 const ImVec2 center =
128 to_screen((r.x0 + r.x1) * 0.5f, (r.y0 + r.y1) * 0.5f);
130 draw_list->AddRectFilled(p0, p1, fill, 3.0f * scale);
131 draw_list->AddRect(p0, p1, stroke, 3.0f * scale, 0, 2.0f);
132 ImVec2 direction(0, 0);
148 ImVec2(center.x + direction.x * 14 * scale,
149 center.y + direction.y * 14 * scale),
156 const ImVec2 p0 = to_screen(r.x0, r.y0);
157 const ImVec2 p1 = to_screen(r.x1, r.y1);
162 std::min(8.0f * scale, std::min(p1.x - p0.x, p1.y - p0.y) * 0.4f);
163 for (
int corner = 0; corner < 4; ++corner) {
164 const bool right = (corner & 1) != 0;
165 const bool bottom = (corner & 2) != 0;
166 const ImVec2 p(right ? p1.x : p0.x, bottom ? p1.y : p0.y);
167 draw_list->AddLine(p, ImVec2(p.x + (right ? -tick : tick), p.y), stroke,
169 draw_list->AddLine(p, ImVec2(p.x, p.y + (bottom ? -tick : tick)),
172 const std::string label =
173 absl::StrFormat(
"$%03X%s%s", shape.
object_id,
180 const ImVec2 p0 = to_screen(r.x0, r.y0);
181 const ImVec2 p1 = to_screen(r.x1, r.y1);
182 draw_list->AddRectFilled(p0, p1, fill);
183 draw_list->AddRect(p0, p1, stroke, 0.0f, 2.0f);
189 std::vector<ImVec2> points;
190 points.reserve(shape.
tiles.size());
191 for (
const auto& tile : shape.
tiles) {
194 points.push_back(to_screen(x, y));
196 const float thickness = std::max(2.0f, 3.0f * scale);
197 draw_list->AddPolyline(points.data(),
static_cast<int>(points.size()),
200 const ImVec2 a = points[points.size() - 2];
201 const ImVec2 b = points.back();
202 DrawArrow(draw_list, a, b, stroke, scale);
203 if (!shape.
label.empty()) {
204 const ImVec2 mid((a.x + b.x) * 0.5f, (a.y + b.y) * 0.5f);
213 const ImVec2 c = to_screen(x, y);
214 const float radius = std::max(5.0f, 5.0f * scale);
215 draw_list->AddCircleFilled(c, radius, stroke);
216 draw_list->AddCircle(c, radius, IM_COL32(255, 255, 255, 230), 0, 1.5f);
224 const ImVec2 c = to_screen(x, y);
225 const float r = std::max(6.0f, 6.0f * scale);
226 const float thickness = std::max(2.0f, 2.5f * scale);
227 draw_list->AddCircle(c, r + 2.0f, stroke, 0, thickness * 0.6f);
228 draw_list->AddLine(ImVec2(c.x - r, c.y - r), ImVec2(c.x + r, c.y + r),
230 draw_list->AddLine(ImVec2(c.x - r, c.y + r), ImVec2(c.x + r, c.y - r),