Skip to content

Commit

Permalink
Add WidgetWithResizeHandle
Browse files Browse the repository at this point in the history
  • Loading branch information
pthom committed Apr 28, 2024
1 parent a2c3617 commit af443a6
Show file tree
Hide file tree
Showing 2 changed files with 131 additions and 2 deletions.
29 changes: 28 additions & 1 deletion src/hello_imgui/hello_imgui_widgets.h
Original file line number Diff line number Diff line change
@@ -1,10 +1,37 @@
#pragma once
// Some additional widgets and utilities for ImGui
#include "imgui.h"
#include <optional>
#include <functional>


namespace HelloImGui
{
using VoidFunction = std::function<void(void)>;

void BeginGroupColumn(); // calls ImGui::BeginGroup()

void EndGroupColumn(); // calls ImGui::EndGroup() + ImGui::SameLine()
}

// WidgetWithResizeHandle: adds a resize handle to a widget
// Example usage with ImPlot:
// void gui()
// {
// static ImVec2 widget_size(200, 200);
// auto myWidgetFunction = []()
// {
// if (ImPlot::BeginPlot("My Plot", widget_size)) {
// ImPlot::PlotLine("My Line", x.data(), y.data(), 1000);
// ImPlot::EndPlot();
// }
// };
// widget_size = widget_with_resize_handle(myWidgetFunction);
// }
ImVec2 WidgetWithResizeHandle(
VoidFunction widgetGuiFunction,
float handleSizeEm = 1.0f,
std::optional<VoidFunction> onItemHovered = std::nullopt,
std::optional<VoidFunction> onItemResized = std::nullopt
);

}
104 changes: 103 additions & 1 deletion src/hello_imgui/impl/hello_imgui_widgets.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#define IMGUI_DEFINE_MATH_OPERATORS
#include "hello_imgui/hello_imgui_widgets.h"

#include "imgui.h"
#include "imgui_internal.h"


namespace HelloImGui
{
Expand All @@ -14,4 +16,104 @@ namespace HelloImGui
ImGui::EndGroup();
ImGui::SameLine();
}


struct WidgetResizingState_
{
bool Resizing = false;
bool MouseInResizingZone = false;
bool MouseDown = false;
ImVec2 MousePosition = ImVec2();
};

static std::unordered_map<ImGuiID, WidgetResizingState_> gWidgetResizingStates;

static WidgetResizingState_* GetWidgetResizingState_(ImGuiID widget_id)
{
if (gWidgetResizingStates.find(widget_id) == gWidgetResizingStates.end())
gWidgetResizingStates[widget_id] = WidgetResizingState_();
return &gWidgetResizingStates.at(widget_id);
}


ImVec2 WidgetWithResizeHandle(
VoidFunction widgetGuiFunction,
float handleSizeEm,
std::optional<VoidFunction> onItemHovered,
std::optional<VoidFunction> onItemResized
)
{
widgetGuiFunction();

if (ImGui::IsMouseHoveringRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax()))
{
if (onItemHovered.has_value() && onItemHovered)
onItemHovered.value()();
}

ImVec2 widget_size = ImGui::GetItemRectSize();
ImGuiID widget_id = ImGui::GetItemID();

float em = ImGui::GetFontSize(), size = em * handleSizeEm;
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 = ImRect(tl, br);

//
// Get and update resizing state
//
WidgetResizingState_* resizingState = GetWidgetResizingState_(widget_id);
WidgetResizingState_ previousResizingState = *resizingState; // This is a copy

resizingState->MousePosition = ImGui::GetIO().MousePos;
resizingState->MouseInResizingZone = ImGui::IsMouseHoveringRect(zone.Min, zone.Max);
resizingState->MouseDown = ImGui::IsMouseDown(0);

ImVec2 mouseDelta = resizingState->MousePosition - previousResizingState.MousePosition;

// Color
ImU32 color = ImGui::GetColorU32(ImGuiCol_Button);
if (ImGui::IsMouseHoveringRect(zone.Min, zone.Max))
color = ImGui::GetColorU32(ImGuiCol_ButtonHovered);
if (resizingState->Resizing)
color = ImGui::GetColorU32(ImGuiCol_ButtonActive);

ImGui::GetWindowDrawList()->AddTriangleFilled(br, bl, tr, color);

if (!resizingState->Resizing)
{
bool wasMouseJustClicked = !previousResizingState.MouseDown && resizingState->MouseDown;
bool mouseInZoneBeforeAfter = previousResizingState.MouseInResizingZone && resizingState->MouseInResizingZone;
if (wasMouseJustClicked && mouseInZoneBeforeAfter)
{
if (onItemResized.has_value() && onItemResized)
onItemResized.value()();
ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeNWSE);
resizingState->Resizing = true;
}
}
if (resizingState->Resizing)
{
if (onItemResized.has_value() && onItemResized)
onItemResized.value()();
if (ImGui::IsMouseDown(0))
{
if (mouseDelta.x != 0.0f || mouseDelta.y != 0.0f)
{
widget_size.x += mouseDelta.x;
widget_size.y += mouseDelta.y;
ImGui::ResetMouseDragDelta(0);
}
}
else
{
ImGui::SetMouseCursor(ImGuiMouseCursor_Arrow);
resizingState->Resizing = false;
}
}

return widget_size;
}

}

0 comments on commit af443a6

Please sign in to comment.