Skip to content

Instantly share code, notes, and snippets.

@pthom
Last active May 11, 2024 07:51
Show Gist options
  • Save pthom/0a532a1d487ded4744f113a7b100511c to your computer and use it in GitHub Desktop.
Save pthom/0a532a1d487ded4744f113a7b100511c to your computer and use it in GitHub Desktop.
// Beware, this code does use `<functional>`
// (because I was lazy. It is possible to rewrite the logic in terms of Begin/End)
// It works if the gui function that you pass as a parameter is nicely grouped
// (i.e. ` ImGui::GetItemID` and `ImGui::GetItemRectSize` will return its correct ID and size)
#include "imgui.h"
#include "imgui_internal.h"
#include <unordered_map>
#include <functional>
using VoidFunction = std::function<void()>;
static std::unordered_map<ImGuiID, bool> gResizingState;
static bool _isResizing(ImGuiID widget_id)
{
if (gResizingState.find(widget_id) == gResizingState.end())
gResizingState[widget_id] = false;
return gResizingState.at(widget_id);
}
static void _setResizing(ImGuiID widget_id, bool value) { gResizingState[widget_id] = value; }
ImVec2 WidgetWithResizeHandle(const char* id, VoidFunction widget_function, float handle_size_em = 1.0f)
{
widget_function();
ImVec2 widget_size = ImGui::GetItemRectSize();
ImGuiID widget_id = ImGui::GetID(id);
float em = ImGui::GetFontSize(), size = em * handle_size_em;
ImVec2 widget_bottom_right = ImGui::GetItemRectMax();
ImVec2 br(widget_bottom_right), bl(br.x - size, br.y), tr(br.x, br.y - size), tl(br.x - size, br.y - size);
ImRect zone(tl, br);
ImU32 color = ImGui::GetColorU32(ImGuiCol_Button);
if (ImGui::IsMouseHoveringRect(zone.Min, zone.Max))
color = ImGui::GetColorU32(ImGuiCol_ButtonHovered);
if (_isResizing(widget_id))
color = ImGui::GetColorU32(ImGuiCol_ButtonActive);
ImGui::GetWindowDrawList()->AddTriangleFilled(br, bl, tr, color);
if (!_isResizing(widget_id))
{
if (ImGui::IsMouseHoveringRect(zone.Min, zone.Max) && ImGui::IsMouseDown(0))
{
ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeNWSE);
_setResizing(widget_id, true);
}
}
if (_isResizing(widget_id))
{
if (ImGui::IsMouseDown(0))
{
ImVec2 mouse_delta = ImGui::GetMouseDragDelta(0);
if (mouse_delta.x != 0.0f || mouse_delta.y != 0.0f)
{
widget_size.x += mouse_delta.x;
widget_size.y += mouse_delta.y;
ImGui::ResetMouseDragDelta(0);
}
}
else
{
ImGui::SetMouseCursor(ImGuiMouseCursor_Arrow);
_setResizing(widget_id, false);
}
}
return widget_size;
}
/*
// Example usage
void gui()
{
static ImVec2 widget_size(200, 200);
auto myWidgetFunction = []()
{
if (ImPlot::BeginPlot("My Plot", widget_size)) {
static std::vector<float> x(1000), y(1000);
for (int i = 0; i < 1000; ++i) {
x[i] = i * 0.01f;
y[i] = std::sin(x[i]);
}
ImPlot::PlotLine("My Line", x.data(), y.data(), 1000);
ImPlot::EndPlot();
}
};
widget_size = WidgetWithResizeHandle("some id", myWidgetFunction);
}
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment