diff options
Diffstat (limited to 'src/imgui_helper_internal.cpp')
-rw-r--r-- | src/imgui_helper_internal.cpp | 222 |
1 files changed, 222 insertions, 0 deletions
diff --git a/src/imgui_helper_internal.cpp b/src/imgui_helper_internal.cpp new file mode 100644 index 0000000..3267dcc --- /dev/null +++ b/src/imgui_helper_internal.cpp @@ -0,0 +1,222 @@ +#include "imgui_internal_widgets.h" + + +#include "imgui.h" +#ifndef IMGUI_DEFINE_MATH_OPERATORS +#define IMGUI_DEFINE_MATH_OPERATORS +#endif +#include "imgui_internal.h" + +// 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, 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 = 0.1; + const float SliderMax = 10; + const float OtherMin = 0; + const float OtherMax = 1; + const void* p_min = &SliderMin; + const void* p_max = &SliderMax; + const void* o_min = &OtherMin; + const void* o_max = &OtherMax; + ImGuiDataType data_type = ImGuiDataType_Float; + const char *format = "%f"; + + ImGuiSliderFlags flags = ImGuiSliderFlags_NoInput; + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + + // 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_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); + const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y * 2.0f)); + const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); + + ItemSize(total_bb, style.FramePadding.y); + + if (!ItemAdd(total_bb, id_L, &frame_bb, 0)) + return false; + if (!ItemAdd(total_bb, id_R, &frame_bb, 0)) + return false; + 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) { + 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) { + 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 | ImGuiSliderFlags_Logarithmic, &grab_bb3); + if (value_changed3) { + MarkItemEdited(id_mid); + any_val_changed = true; + } + + 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_L || g.NavActivateInputId == id_L); + + if (make_active) + { + if (g.IO.MousePos.x < grab_bb.Max.x) { + SetActiveID(id_L, window); + SetFocusID(id_L, window); + } else if (g.IO.MousePos.x > grab_bb2.Min.x) { + SetActiveID(id_R, window); + SetFocusID(id_R, window); + } else { + SetActiveID(id_mid, window); + SetFocusID(id_mid, window); + } + FocusWindow(window); + g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right); + } + + + // Draw frame + const ImU32 frame_col = GetColorU32(g.ActiveId == id_L ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); + RenderNavHighlight(frame_bb, id_L); + RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, g.Style.FrameRounding); + + + // Render grab + if (grab_bb.Max.x > grab_bb.Min.x) + window->DrawList->AddRectFilled(grab_bb.Min, grab_bb.Max, GetColorU32(g.ActiveId == id_L ? ImGuiCol_SliderGrabActive : ImGuiCol_SliderGrab), style.GrabRounding); + + + // Render grab + if (grab_bb2.Max.x > grab_bb2.Min.x) + window->DrawList->AddRectFilled(grab_bb2.Min, grab_bb2.Max, GetColorU32(g.ActiveId == id_R ? ImGuiCol_SliderGrabActive : ImGuiCol_SliderGrab), style.GrabRounding); + + + // Render grab + if (grab_bb3.Max.x > grab_bb3.Min.x) + window->DrawList->AddRectFilled(grab_bb3.Min, grab_bb3.Max, GetColorU32(g.ActiveId == id_mid ? ImGuiCol_SliderGrabActive : ImGuiCol_SliderGrab), style.GrabRounding); + + // 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_mid, format); + if (g.LogEnabled) + LogSetNextTextDecoration("{", "}"); + RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f, 0.5f)); + + if (label_size.x > 0.0f) + 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 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 (ImFabs(g.IO.MousePos.x - point.x) < 3 && ImFabs(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; +} + +// Currently not used anywhere outside of debug UI. I'll keep it in case +// there's a place where doing this operation in UI space is useful. Note that +// the version of this function in bezier.cpp differs in precision by about +// 0.001. + +ImVec2 ImGui::RatioToPoint(ImVec2 a, 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; +} + +// Returns true when cursor is close to the curve but not too close to the +// beginning/end points. Basically just a wrapper for that ClosestPoint +// function. +bool ImGui::BezierInteractive(ImVec2 p0, ImVec2 p1, ImVec2 p2, ImVec2 p3) +{ + bool hovered = false; + + ImGuiContext& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImVec2 point = ImBezierCubicClosestPointCasteljau(p0, p1, p2, p3, g.IO.MousePos, GetStyle().CurveTessellationTol); + + if (ImFabs(g.IO.MousePos.x - point.x) < 3 && ImFabs(g.IO.MousePos.y - point.y) < 3 && + ImFabs(p0.x - point.x) > 3 && ImFabs(p0.y - point.y) > 3 && + ImFabs(p1.x - point.x) > 3 && ImFabs(p1.y - point.y) > 3) + { + hovered = true; + } + + return hovered; +} + +bool ImGui::LineInteractive(ImVec2 p0, ImVec2 p1) +{ + bool hovered = false; + + ImGuiContext& g = *GImGui; + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return false; + + ImVec2 point = ImLineClosestPoint(p0, p1, g.IO.MousePos); + + if (ImFabs(g.IO.MousePos.x - point.x) < 3 && ImFabs(g.IO.MousePos.y - point.y) < 3 && + ImFabs(p0.x - point.x) > 3 && ImFabs(p0.y - point.y) > 3 && + ImFabs(p1.x - point.x) > 3 && ImFabs(p1.y - point.y) > 3) + { + hovered = true; + } + + return hovered; +} |