aboutsummaryrefslogtreecommitdiff
path: root/source/EditorUtils.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/EditorUtils.cpp')
-rw-r--r--source/EditorUtils.cpp261
1 files changed, 260 insertions, 1 deletions
diff --git a/source/EditorUtils.cpp b/source/EditorUtils.cpp
index 39d66fb..20caef7 100644
--- a/source/EditorUtils.cpp
+++ b/source/EditorUtils.cpp
@@ -4,8 +4,10 @@
#include <imgui_internal.h>
#include <backends/imgui_impl_glfw.h>
+#include <cmath>
#include <glm/gtc/quaternion.hpp>
#include <glm/gtx/quaternion.hpp>
+#include <numbers>
const char* ImGui::GetKeyNameGlfw(int key) {
return GetKeyName(ImGui_ImplGlfw_KeyToImGuiKey(key));
@@ -163,13 +165,270 @@ bool ImGui::Splitter(bool splitVertically, float thickness, float* size1, float*
return held;
}
-void ImGui ::AddUnderLine(ImColor col) {
+void ImGui::AddUnderLine(ImColor col) {
auto min = ImGui::GetItemRectMin();
auto max = ImGui::GetItemRectMax();
min.y = max.y;
ImGui::GetWindowDrawList()->AddLine(min, max, col, 1.0f);
}
+void ImGui::DrawIcon(ImDrawList* drawList, const ImVec2& a, const ImVec2& b, IconType type, bool filled, ImU32 color, ImU32 innerColor) {
+ // Taken from https://github.com/thedmd/imgui-node-editor/blob/master/examples/blueprints-example/utilities/drawing.cpp
+ // ax::NodeEditor::DrawIcon
+
+ auto rect = ImRect(a, b);
+ auto rect_x = rect.Min.x;
+ auto rect_y = rect.Min.y;
+ auto rect_w = rect.Max.x - rect.Min.x;
+ auto rect_h = rect.Max.y - rect.Min.y;
+ auto rect_center_x = (rect.Min.x + rect.Max.x) * 0.5f;
+ auto rect_center_y = (rect.Min.y + rect.Max.y) * 0.5f;
+ auto rect_center = ImVec2(rect_center_x, rect_center_y);
+ const auto outline_scale = rect_w / 24.0f;
+ const auto extra_segments = static_cast<int>(2 * outline_scale); // for full circle
+
+ if (type == IconType::Flow) {
+ const auto origin_scale = rect_w / 24.0f;
+
+ const auto offset_x = 1.0f * origin_scale;
+ const auto offset_y = 0.0f * origin_scale;
+ const auto margin = 2.0f * origin_scale;
+ const auto rounding = 0.1f * origin_scale;
+ const auto tip_round = 0.7f; // percentage of triangle edge (for tip)
+ // const auto edge_round = 0.7f; // percentage of triangle edge (for corner)
+ const auto canvas = ImRect(
+ rect.Min.x + margin + offset_x,
+ rect.Min.y + margin + offset_y,
+ rect.Max.x - margin + offset_x,
+ rect.Max.y - margin + offset_y);
+ const auto canvas_x = canvas.Min.x;
+ const auto canvas_y = canvas.Min.y;
+ const auto canvas_w = canvas.Max.x - canvas.Min.x;
+ const auto canvas_h = canvas.Max.y - canvas.Min.y;
+
+ const auto left = canvas_x + canvas_w * 0.5f * 0.3f;
+ const auto right = canvas_x + canvas_w - canvas_w * 0.5f * 0.3f;
+ const auto top = canvas_y + canvas_h * 0.5f * 0.2f;
+ const auto bottom = canvas_y + canvas_h - canvas_h * 0.5f * 0.2f;
+ const auto center_y = (top + bottom) * 0.5f;
+ // const auto angle = AX_PI * 0.5f * 0.5f * 0.5f;
+
+ const auto tip_top = ImVec2(canvas_x + canvas_w * 0.5f, top);
+ const auto tip_right = ImVec2(right, center_y);
+ const auto tip_bottom = ImVec2(canvas_x + canvas_w * 0.5f, bottom);
+
+ drawList->PathLineTo(ImVec2(left, top) + ImVec2(0, rounding));
+ drawList->PathBezierCubicCurveTo(
+ ImVec2(left, top),
+ ImVec2(left, top),
+ ImVec2(left, top) + ImVec2(rounding, 0));
+ drawList->PathLineTo(tip_top);
+ drawList->PathLineTo(tip_top + (tip_right - tip_top) * tip_round);
+ drawList->PathBezierCubicCurveTo(
+ tip_right,
+ tip_right,
+ tip_bottom + (tip_right - tip_bottom) * tip_round);
+ drawList->PathLineTo(tip_bottom);
+ drawList->PathLineTo(ImVec2(left, bottom) + ImVec2(rounding, 0));
+ drawList->PathBezierCubicCurveTo(
+ ImVec2(left, bottom),
+ ImVec2(left, bottom),
+ ImVec2(left, bottom) - ImVec2(0, rounding));
+
+ if (!filled) {
+ if (innerColor & 0xFF000000) {
+ drawList->AddConvexPolyFilled(drawList->_Path.Data, drawList->_Path.Size, innerColor);
+ }
+
+ drawList->PathStroke(color, true, 2.0f * outline_scale);
+ } else {
+ drawList->PathFillConvex(color);
+ }
+ } else {
+ auto triangleStart = rect_center_x + 0.32f * rect_w;
+
+ auto rect_offset = -static_cast<int>(rect_w * 0.25f * 0.25f);
+
+ rect.Min.x += rect_offset;
+ rect.Max.x += rect_offset;
+ rect_x += rect_offset;
+ rect_center_x += rect_offset * 0.5f;
+ rect_center.x += rect_offset * 0.5f;
+
+ if (type == IconType::Circle) {
+ const auto c = rect_center;
+
+ if (!filled) {
+ const auto r = 0.5f * rect_w / 2.0f - 0.5f;
+
+ if (innerColor & 0xFF000000)
+ drawList->AddCircleFilled(c, r, innerColor, 12 + extra_segments);
+ drawList->AddCircle(c, r, color, 12 + extra_segments, 2.0f * outline_scale);
+ } else {
+ drawList->AddCircleFilled(c, 0.5f * rect_w / 2.0f, color, 12 + extra_segments);
+ }
+ }
+
+ if (type == IconType::Square) {
+ if (filled) {
+ const auto r = 0.5f * rect_w / 2.0f;
+ const auto p0 = rect_center - ImVec2(r, r);
+ const auto p1 = rect_center + ImVec2(r, r);
+
+ drawList->AddRectFilled(p0, p1, color, 0, 15 + extra_segments);
+ } else {
+ const auto r = 0.5f * rect_w / 2.0f - 0.5f;
+ const auto p0 = rect_center - ImVec2(r, r);
+ const auto p1 = rect_center + ImVec2(r, r);
+
+ if (innerColor & 0xFF000000)
+ drawList->AddRectFilled(p0, p1, innerColor, 0, 15 + extra_segments);
+
+ drawList->AddRect(p0, p1, color, 0, 15 + extra_segments, 2.0f * outline_scale);
+ }
+ }
+
+ if (type == IconType::Grid) {
+ const auto r = 0.5f * rect_w / 2.0f;
+ const auto w = ceilf(r / 3.0f);
+
+ const auto baseTl = ImVec2(floorf(rect_center_x - w * 2.5f), floorf(rect_center_y - w * 2.5f));
+ const auto baseBr = ImVec2(floorf(baseTl.x + w), floorf(baseTl.y + w));
+
+ auto tl = baseTl;
+ auto br = baseBr;
+ for (int i = 0; i < 3; ++i) {
+ tl.x = baseTl.x;
+ br.x = baseBr.x;
+ drawList->AddRectFilled(tl, br, color);
+ tl.x += w * 2;
+ br.x += w * 2;
+ if (i != 1 || filled)
+ drawList->AddRectFilled(tl, br, color);
+ tl.x += w * 2;
+ br.x += w * 2;
+ drawList->AddRectFilled(tl, br, color);
+
+ tl.y += w * 2;
+ br.y += w * 2;
+ }
+
+ triangleStart = br.x + w + 1.0f / 24.0f * rect_w;
+ }
+
+ if (type == IconType::RoundSquare) {
+ if (filled) {
+ const auto r = 0.5f * rect_w / 2.0f;
+ const auto cr = r * 0.5f;
+ const auto p0 = rect_center - ImVec2(r, r);
+ const auto p1 = rect_center + ImVec2(r, r);
+
+ drawList->AddRectFilled(p0, p1, color, cr, 15);
+ } else {
+ const auto r = 0.5f * rect_w / 2.0f - 0.5f;
+ const auto cr = r * 0.5f;
+ const auto p0 = rect_center - ImVec2(r, r);
+ const auto p1 = rect_center + ImVec2(r, r);
+
+ if (innerColor & 0xFF000000)
+ drawList->AddRectFilled(p0, p1, innerColor, cr, 15);
+
+ drawList->AddRect(p0, p1, color, cr, 15, 2.0f * outline_scale);
+ }
+ } else if (type == IconType::Diamond) {
+ if (filled) {
+ const auto r = 0.607f * rect_w / 2.0f;
+ const auto c = rect_center;
+
+ drawList->PathLineTo(c + ImVec2(0, -r));
+ drawList->PathLineTo(c + ImVec2(r, 0));
+ drawList->PathLineTo(c + ImVec2(0, r));
+ drawList->PathLineTo(c + ImVec2(-r, 0));
+ drawList->PathFillConvex(color);
+ } else {
+ const auto r = 0.607f * rect_w / 2.0f - 0.5f;
+ const auto c = rect_center;
+
+ drawList->PathLineTo(c + ImVec2(0, -r));
+ drawList->PathLineTo(c + ImVec2(r, 0));
+ drawList->PathLineTo(c + ImVec2(0, r));
+ drawList->PathLineTo(c + ImVec2(-r, 0));
+
+ if (innerColor & 0xFF000000)
+ drawList->AddConvexPolyFilled(drawList->_Path.Data, drawList->_Path.Size, innerColor);
+
+ drawList->PathStroke(color, true, 2.0f * outline_scale);
+ }
+ } else {
+ const auto triangleTip = triangleStart + rect_w * (0.45f - 0.32f);
+
+ drawList->AddTriangleFilled(
+ ImVec2(ceilf(triangleTip), rect_y + rect_h * 0.5f),
+ ImVec2(triangleStart, rect_center_y + 0.15f * rect_h),
+ ImVec2(triangleStart, rect_center_y - 0.15f * rect_h),
+ color);
+ }
+ }
+}
+
+void ImGui::Icon(const ImVec2& size, IconType type, bool filled, const ImVec4& color, const ImVec4& innerColor) {
+ // Taken from https://github.com/thedmd/imgui-node-editor/blob/master/examples/blueprints-example/utilities/widgets.cpp
+ // ax::NodeEditor::Icon
+
+ if (ImGui::IsRectVisible(size)) {
+ auto cursorPos = ImGui::GetCursorScreenPos();
+ auto drawList = ImGui::GetWindowDrawList();
+ DrawIcon(drawList, cursorPos, cursorPos + size, type, filled, ImColor(color), ImColor(innerColor));
+ }
+
+ ImGui::Dummy(size);
+}
+
+void ImGui::DrawArrow(ImDrawList* drawList, ImVec2 from, ImVec2 to, ImU32 color, float lineThickness) {
+ // Adapted from https://stackoverflow.com/a/6333775
+
+ using namespace std::numbers;
+ constexpr float kHeadLength = 10;
+
+ auto angle = std::atan2(to.y - from.y, to.x - from.x);
+ drawList->AddLine(from, to, color, lineThickness);
+ drawList->AddLine(to, ImVec2(to.x - kHeadLength * std::cos(angle - pi / 6), to.y - kHeadLength * std::sin(angle - pi / 6)), color, lineThickness);
+ drawList->AddLine(to, ImVec2(to.x - kHeadLength * std::cos(angle + pi / 6), to.y - kHeadLength * std::sin(angle + pi / 6)), color, lineThickness);
+}
+
+struct DialogObject {
+ std::string message;
+ std::function<void(int)> callback;
+};
+
+static DialogObject gConfirmationDialog{};
+
+void ImGui::DialogConfirmation(std::string message, std::function<void(bool)> callback) {
+ gConfirmationDialog.message = std::move(message);
+ // TODO is converting void(bool) to void(int) fine?
+ gConfirmationDialog.callback = std::move(callback);
+}
+
+void ImGui::ShowDialogs() {
+ if (gConfirmationDialog.callback) {
+ if (ImGui::BeginPopupModal("Confirmation")) {
+ ImGui::Text("%s", gConfirmationDialog.message.c_str());
+ if (ImGui::Button("Cancel")) {
+ gConfirmationDialog.callback(false);
+ gConfirmationDialog.callback = {};
+ ImGui::CloseCurrentPopup();
+ }
+ ImGui::SameLine();
+ if (ImGui::Button("Confirm")) {
+ gConfirmationDialog.callback(true);
+ gConfirmationDialog.callback = {};
+ ImGui::CloseCurrentPopup();
+ }
+ ImGui::EndPopup();
+ }
+ }
+}
+
float Utils::CalcImageHeight(glm::vec2 original, int targetWidth) {
// Xorig / Yorig = Xnew / Ynew
// Ynew = Xnew * Yorig / Xorig