Basic rectangle selection in content browser

This commit is contained in:
Simon Lübeß
2025-07-04 00:13:33 +02:00
parent b00119b41e
commit e3c7057dce
3 changed files with 382 additions and 33 deletions
+89
View File
@@ -38,6 +38,95 @@ namespace ImGui
public static explicit operator float4(Vec4 v) => .(v.x, v.y, v.z, v.w);
public static explicit operator Vec4(float4 v) => .(v.X, v.Y, v.Z, v.W);
}
extension Color
{
public static explicit operator ColorRGBA(Color c) => .(c.Value.x, c.Value.y, c.Value.z, c.Value.w);
public static explicit operator Color(ColorRGBA c) => .(c.R, c.G, c.B, c.A);
}
enum RectangleSelectionFlags
{
None,
NoRender
}
public static bool BeginRectangleSelection(ref float4 selectionRectangle, bool isMouseDown, RectangleSelectionFlags flags = .None)
{
/*let storage = ImGui.GetStateStorage();
ref float selectionRectX = ref *storage.GetFloatRef(ImGui.GetID("SelectionRect.X"), float.NaN);*/
float2 minRegion = (.)ImGui.GetCursorPos() + (.)ImGui.GetWindowPos();
float2 maxRegion = minRegion + (float2)ImGui.GetContentRegionAvail();
ImGui.DrawRect((.)minRegion, (.)maxRegion, ImGui.Color(0,1f,0));
bool selectionValid() => !any(isnan(selectionRectangle));
if (isMouseDown)
{
if (!selectionValid() && IsWindowHovered())
{
selectionRectangle.XY = (float2)ImGui.GetMousePos();
}
selectionRectangle.ZW = (.)ImGui.GetMousePos();
}
else
{
selectionRectangle.XYZW = float.NaN;
return false;
}
selectionRectangle.XY = clamp(selectionRectangle.XY, minRegion, maxRegion);
selectionRectangle.ZW = clamp(selectionRectangle.ZW, minRegion, maxRegion);
if (!flags.HasFlag(.NoRender) && selectionValid())
{
let drawList = ImGui.GetForegroundDrawList();
drawList.AddRect((.)selectionRectangle.XY, (.)selectionRectangle.ZW, ImGui.GetColorU32(ImGui.Color(0, 130, 216, 255).Value));
drawList.AddRectFilled((.)selectionRectangle.XY, (.)selectionRectangle.ZW, ImGui.GetColorU32(ImGui.Color(0, 130, 216, 50).Value));
}
return true;
}
/// Returns true if the user is currently doing a rectangle selection
public static bool IsRectangleSelecting(ref float4 selectionRectangle)
{
return !any(isnan(selectionRectangle));
}
/// Returns true if the current item is intersecting the selection rectangle
public static bool IsInRectangleSelection(ref float4 selectionRectangle)
{
if (any(isnan(selectionRectangle)))
{
return false;
}
ImGui.DebugDrawItemRect();
float2 minRect = (.)ImGui.GetItemRectMin();
float2 maxRect = (.)ImGui.GetItemRectMax();
float2 topLeft = min(minRect, maxRect);
float2 bottomRight = max(minRect, maxRect);
Rectangle itemRectangle = .(topLeft, 0);
itemRectangle.BottomRight = bottomRight;
let drawList = ImGui.GetForegroundDrawList();
drawList.AddRect((.)itemRectangle.TopLeft, (.)itemRectangle.BottomRight, ImGui.GetColorU32(ImGui.Color(0, 130, 216, 255).Value));
float2 selectionTopLeft = min(selectionRectangle.XY, selectionRectangle.ZW);
float2 selectionTottomRight = max(selectionRectangle.XY, selectionRectangle.ZW);
Rectangle rect = .(selectionTopLeft, 0);
rect.BottomRight = selectionTottomRight;
return rect.Intersects(itemRectangle);
}
public static Payload<T>? AcceptDragDropPayload<T>(char8* type, DragDropFlags flags = .None) where T : struct
{
+110
View File
@@ -0,0 +1,110 @@
using Bon;
using System;
namespace GlitchyEngine.Math;
enum IntersectionMode
{
Disjoint,
Intersects,
Contains
}
[BonTarget, CRepr]
struct Rectangle
{
private float2 _topLeft;
private float2 _size;
public float2 TopLeft
{
get => _topLeft;
set mut => _topLeft = value;
}
public float2 Size
{
get => _size;
set mut => _size = value;
}
public float2 BottomRight
{
get => _topLeft + _size;
set mut
{
_size = value - _topLeft;
if (_size.X < 0)
{
_size.X = -_size.X;
_topLeft.X = value.X;
}
if (_size.Y < 0)
{
_size.Y = -_size.Y;
_topLeft.Y = value.Y;
}
}
}
public float Left
{
get => _topLeft.X;
set mut => _topLeft.X = value;
}
public float Top
{
get => _topLeft.Y;
set mut => _topLeft.Y = value;
}
public float Right
{
get => _topLeft.X + _size.X;
set mut => _size.X = value - _topLeft.X;
}
public float Bottom
{
get => _topLeft.Y + _size.Y;
set mut => _size.Y = value - _topLeft.Y;
}
public this(float2 topLeft, float2 size)
{
_topLeft = topLeft;
_size = size;
}
public bool Contains(float2 point)
{
return all(_topLeft <= point) && all(BottomRight >= point);
}
public IntersectionMode Collision(Rectangle other)
{
if (any(other.TopLeft >= this.BottomRight) || any(other.BottomRight <= this.TopLeft))
{
return .Disjoint;
}
if (all(other.TopLeft >= this.TopLeft) && all(other.BottomRight <= this.BottomRight))
{
return .Contains;
}
return .Intersects;
}
public bool Intersects(Rectangle other)
{
return !(other.Left > Right
|| other.Top > Bottom
|| other.Right < Left
|| other.Bottom < Top
);
}
}