summaryrefslogtreecommitdiff
path: root/my_imgui_internal_widgets.cpp
diff options
context:
space:
mode:
authorFox Caminiti <fox@foxcam.net>2022-08-08 13:50:34 -0400
committerFox Caminiti <fox@foxcam.net>2022-08-08 13:50:34 -0400
commit635576972024319c15141645d3304db8cd1d1e19 (patch)
tree425bcebd621449cd89973fbf4803c22a9b83a335 /my_imgui_internal_widgets.cpp
parentbccb1d61907fea45c5e84b29499989f7cee104a5 (diff)
basic bezier path system added
Diffstat (limited to 'my_imgui_internal_widgets.cpp')
-rw-r--r--my_imgui_internal_widgets.cpp187
1 files changed, 168 insertions, 19 deletions
diff --git a/my_imgui_internal_widgets.cpp b/my_imgui_internal_widgets.cpp
index d8934d8..c654e36 100644
--- a/my_imgui_internal_widgets.cpp
+++ b/my_imgui_internal_widgets.cpp
@@ -1,5 +1,7 @@
#include "my_imgui_internal_widgets.h"
+
+
#include "imgui.h"
#ifndef IMGUI_DEFINE_MATH_OPERATORS
#define IMGUI_DEFINE_MATH_OPERATORS
@@ -9,14 +11,14 @@
// A modded version of ScalarSlider allowing for the minimum and maximum parts
// of the slider to be draggable by two other buttons. p_mid is from range -1
// to 1, and s_min and max are from 0-1.
-bool ImGui::SliderLevels(const char* label, void* p_mid, void* p_left, void* p_right)
+bool ImGui::SliderLevels(const char* label, const char* label2, const char* label3, void* p_mid, void* p_left, void* p_right)
{
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems)
return false;
- const float SliderMin = -1;
- const float SliderMax = 1;
+ const float SliderMin = 0.1;
+ const float SliderMax = 10;
const float OtherMin = 0;
const float OtherMax = 1;
const void* p_min = &SliderMin;
@@ -32,14 +34,9 @@ bool ImGui::SliderLevels(const char* label, void* p_mid, void* p_left, void* p_r
// I'm not well-versed in exactly what ImGui's id system does, but I'm
// pretty sure it's one clickable object equals one ImGui ID.
- const ImGuiID id = window->GetID(label);
- PushID(label);
- PushID(1);
- const ImGuiID id_L = window->GetID("");
- PopID();
- PopID();
- const ImGuiID id_R = window->GetID("adsafb");
- const ImGuiID id_mid = window->GetID("asdasbdsgd");
+ const ImGuiID id_L = window->GetID(label);
+ const ImGuiID id_R = window->GetID(label2);
+ const ImGuiID id_mid = window->GetID(label3);
const float w = CalcItemWidth();
const ImVec2 label_size = CalcTextSize(label, NULL, true);
@@ -55,30 +52,37 @@ bool ImGui::SliderLevels(const char* label, void* p_mid, void* p_left, void* p_r
if (!ItemAdd(total_bb, id_mid, &frame_bb, 0))
return false;
+ bool any_val_changed;
// Slider behavior
ImRect grab_bb;
const bool value_changed = SliderBehavior(frame_bb, id_L, data_type, p_left, o_min, o_max, format, flags, &grab_bb);
- if (value_changed)
+ if (value_changed) {
MarkItemEdited(id_L);
+ any_val_changed = true;
+ }
ImRect grab_bb2;
const bool value_changed2 = SliderBehavior(frame_bb, id_R, data_type, p_right, o_min, o_max, format, flags, &grab_bb2);
- if (value_changed2)
+ if (value_changed2) {
MarkItemEdited(id_R);
+ any_val_changed = true;
+ }
const ImRect mid_bb(ImVec2(grab_bb.Max.x, frame_bb.Min.y), ImVec2(grab_bb2.Min.x, frame_bb.Max.y));
// Slider behavior
ImRect grab_bb3;
- const bool value_changed3 = SliderBehavior(mid_bb, id_mid, data_type, p_mid, p_min, p_max, format, flags, &grab_bb3);
- if (value_changed3)
+ const bool value_changed3 = SliderBehavior(mid_bb, id_mid, data_type, p_mid, p_min, p_max, format, flags | ImGuiSliderFlags_Logarithmic, &grab_bb3);
+ if (value_changed3) {
MarkItemEdited(id_mid);
+ any_val_changed = true;
+ }
- const bool hovered = ItemHoverable(frame_bb, id);
+ const bool hovered = ItemHoverable(frame_bb, id_L);
const bool input_requested_by_tabbing = (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_FocusedByTabbing) != 0;
const bool clicked = (hovered && g.IO.MouseClicked[0]);
- const bool make_active = (input_requested_by_tabbing || clicked || g.NavActivateId == id || g.NavActivateInputId == id);
+ const bool make_active = (input_requested_by_tabbing || clicked || g.NavActivateId == id_L || g.NavActivateInputId == id_L);
if (make_active)
{
@@ -119,7 +123,7 @@ bool ImGui::SliderLevels(const char* label, void* p_mid, void* p_left, void* p_r
// Display value using user-provided display format so user can add prefix/suffix/decorations to the value.
char value_buf[64];
- const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_ARRAYSIZE(value_buf), data_type, p_left, format);
+ const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_ARRAYSIZE(value_buf), data_type, p_mid, format);
if (g.LogEnabled)
LogSetNextTextDecoration("{", "}");
RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f, 0.5f));
@@ -128,5 +132,150 @@ bool ImGui::SliderLevels(const char* label, void* p_mid, void* p_left, void* p_r
RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags);
- return value_changed;
+ return any_val_changed;
+}
+
+bool ImGui::TestLine(ImVec2 p0, ImVec2 p1)
+{
+ ImGuiContext& g = *GImGui;
+ ImGuiWindow* window = GetCurrentWindow();
+ if (window->SkipItems)
+ return false;
+
+ bool Toggle = false;
+
+ ImDrawList* draw_list = window->DrawList;
+ // ImGuiStyle& style = g.Style;
+
+ ImVec2 point = ImLineClosestPoint(p0, p1, g.IO.MousePos);
+
+ ImU32 col = ImGui::GetColorU32(ImGuiCol_ScrollbarGrab);
+
+ if (abs(g.IO.MousePos.x - point.x) < 3 && abs(g.IO.MousePos.y - point.y) < 3 &&
+ point.x != p0.x && point.y != p0.y &&
+ point.x != p1.x && point.y != p1.y)
+ {
+ col = ImGui::GetColorU32(ImGuiCol_Button);
+ Toggle = true;
+ }
+
+ draw_list->AddLine(p0, p1, col, 2.0f);
+
+ return Toggle;
+}
+
+// Slightly modified version of the bezier closest point lookup code that
+// additionally outputs the ratio of the closest point along the curve for use
+// in constructing the handles of new points.
+
+
+// The ratio here is just the dot product divided by the squared length.
+ImVec2 ImLineClosestPoint2(const ImVec2& a, const ImVec2& b, const ImVec2& p, float& ratio)
+{
+ ImVec2 ap = p - a;
+ ImVec2 ab_dir = b - a;
+ float dot = ap.x * ab_dir.x + ap.y * ab_dir.y;
+ if (dot < 0.0f) {
+ ratio = 0.0f;
+ return a;
+ }
+ float ab_len_sqr = ab_dir.x * ab_dir.x + ab_dir.y * ab_dir.y;
+ if (dot > ab_len_sqr) {
+ ratio = 1.0f;
+ return b;
+ }
+ ratio = dot / ab_len_sqr;
+ return a + ab_dir * dot / ab_len_sqr;
+}
+
+// Function to convert a ratio back into a point for the bezier handles.
+ImVec2 ImGui::RatioToPoint(const ImVec2& a, const ImVec2& b, float ratio)
+{
+ ImVec2 ab_dir = b - a;
+ float ab_len_sqr = ab_dir.x * ab_dir.x + ab_dir.y * ab_dir.y;
+ float dot = ratio*ab_len_sqr;
+ return a + ab_dir * dot / ab_len_sqr;
+}
+
+
+// Following the algorithm, we take the ratio from the _leftmost_ point in each
+// subdivision of the cubic spline until we're within tess_tol, and then we
+// interpolate it with the subdivision's rightmost point in the ClosestPoint call.
+// The pow(0.5, level) represents the ratio of the next subdivision's leftmost
+// point (AKA the rightmost point of the current subdivision).
+
+static void ImBezierCubicClosestPointCasteljauStep2(const ImVec2& p, ImVec2& p_closest, float ratio, float& r_closest, ImVec2& p_last, float& p_closest_dist2, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, float tess_tol, int level)
+{
+ float dx = x4 - x1;
+ float dy = y4 - y1;
+ float d2 = ((x2 - x4) * dy - (y2 - y4) * dx);
+ float d3 = ((x3 - x4) * dy - (y3 - y4) * dx);
+ d2 = (d2 >= 0) ? d2 : -d2;
+ d3 = (d3 >= 0) ? d3 : -d3;
+ if ((d2 + d3) * (d2 + d3) < tess_tol * (dx * dx + dy * dy))
+ {
+ ImVec2 p_current(x4, y4);
+ float added_ratio;
+ ImVec2 p_line = ImLineClosestPoint2(p_last, p_current, p, added_ratio);
+ float dist2 = ImLengthSqr(p - p_line);
+ if (dist2 < p_closest_dist2)
+ {
+ p_closest = p_line;
+ p_closest_dist2 = dist2;
+ r_closest = ratio + pow(0.5, level)*added_ratio;
+ }
+ p_last = p_current;
+ }
+ else if (level < 10)
+ {
+ float x12 = (x1 + x2)*0.5f, y12 = (y1 + y2)*0.5f;
+ float x23 = (x2 + x3)*0.5f, y23 = (y2 + y3)*0.5f;
+ float x34 = (x3 + x4)*0.5f, y34 = (y3 + y4)*0.5f;
+ float x123 = (x12 + x23)*0.5f, y123 = (y12 + y23)*0.5f;
+ float x234 = (x23 + x34)*0.5f, y234 = (y23 + y34)*0.5f;
+ float x1234 = (x123 + x234)*0.5f, y1234 = (y123 + y234)*0.5f;
+ ImBezierCubicClosestPointCasteljauStep2(p, p_closest, ratio, r_closest, p_last, p_closest_dist2, x1, y1, x12, y12, x123, y123, x1234, y1234, tess_tol, level + 1);
+ ImBezierCubicClosestPointCasteljauStep2(p, p_closest, ratio + pow(0.5, level+1), r_closest, p_last, p_closest_dist2, x1234, y1234, x234, y234, x34, y34, x4, y4, tess_tol, level + 1);
+ }
+}
+
+ImVec2 ImBezierCubicClosestPointCasteljau2(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, float& ratio, float tess_tol)
+{
+ IM_ASSERT(tess_tol > 0.0f);
+ ImVec2 p_last = p1;
+ ImVec2 p_closest;
+ float p_closest_dist2 = FLT_MAX;
+ float r_closest;
+ ImBezierCubicClosestPointCasteljauStep2(p, p_closest, 0, r_closest, p_last, p_closest_dist2, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, tess_tol, 0);
+ ratio = r_closest;
+ return p_closest;
+}
+
+// Returns true when cursor is close to the curve but not too close to the beginning/end points.
+bool ImGui::BezierInteractive(ImVec2 p0, ImVec2 p1, ImVec2 p2, ImVec2 p3, float& ratio)
+{
+ bool hovered = false;
+
+ ImGuiContext& g = *GImGui;
+ ImGuiWindow* window = GetCurrentWindow();
+ if (window->SkipItems)
+ return false;
+
+ ImDrawList* draw_list = window->DrawList;
+ ImU32 col = ImGui::GetColorU32(ImGuiCol_ScrollbarGrab);
+
+ ImVec2 point = ImBezierCubicClosestPointCasteljau2(p0, p1, p2, p3, g.IO.MousePos, ratio, GetStyle().CurveTessellationTol);
+
+
+ if (abs(g.IO.MousePos.x - point.x) < 3 && abs(g.IO.MousePos.y - point.y) < 3 &&
+ abs(p0.x - point.x) > 3 && abs(p0.y - point.y) > 3 &&
+ abs(p1.x - point.x) > 3 && abs(p1.y - point.y) > 3)
+ {
+ col = GetColorU32(ImGuiCol_Button);
+ hovered = true;
+ }
+
+ draw_list->AddBezierCubic(p0, p1, p2, p3, col, 2.0f, 0);
+
+ return hovered;
}