Replaced C style array manipulation
This commit is contained in:
parent
e194ec7a3f
commit
cdc54751a3
@ -149,37 +149,37 @@ namespace MicroUI
|
||||
[System.Flags]
|
||||
public enum Options
|
||||
{
|
||||
AlignCenter = 1 << 0, // 1
|
||||
AlignRight = 1 << 1, // 2
|
||||
NoInteract = 1 << 2, // 4
|
||||
NoFrame = 1 << 3, // 8
|
||||
NoResize = 1 << 4, // 16
|
||||
NoScroll = 1 << 5, // 32
|
||||
NoClose = 1 << 6, // 64
|
||||
NoTitle = 1 << 7, // 128
|
||||
HoldFocus = 1 << 8, // 256
|
||||
AutoSize = 1 << 9, // 512
|
||||
Popup = 1 << 10, // 1024
|
||||
Closed = 1 << 11, // 2048
|
||||
Expanded = 1 << 12 // 4096
|
||||
AlignCenter = 1 << 0,
|
||||
AlignRight = 1 << 1,
|
||||
NoInteract = 1 << 2,
|
||||
NoFrame = 1 << 3,
|
||||
NoResize = 1 << 4,
|
||||
NoScroll = 1 << 5,
|
||||
NoClose = 1 << 6,
|
||||
NoTitle = 1 << 7,
|
||||
HoldFocus = 1 << 8,
|
||||
AutoSize = 1 << 9,
|
||||
Popup = 1 << 10,
|
||||
Closed = 1 << 11,
|
||||
Expanded = 1 << 12
|
||||
}
|
||||
|
||||
[System.Flags]
|
||||
public enum MouseButton
|
||||
{
|
||||
Left = 1 << 0, // 1
|
||||
Right = 1 << 1, // 2
|
||||
Middle = 1 << 2 // 4
|
||||
Left = 1 << 0,
|
||||
Right = 1 << 1,
|
||||
Middle = 1 << 2
|
||||
}
|
||||
|
||||
[System.Flags]
|
||||
public enum KeyModifiers
|
||||
{
|
||||
Shift = 1 << 0, // 1
|
||||
Ctrl = 1 << 1, // 2
|
||||
Alt = 1 << 2, // 4
|
||||
Backspace = 1 << 3, // 8
|
||||
Return = 1 << 4 // 16
|
||||
Shift = 1 << 0,
|
||||
Ctrl = 1 << 1,
|
||||
Alt = 1 << 2,
|
||||
Backspace = 1 << 3,
|
||||
Return = 1 << 4
|
||||
}
|
||||
|
||||
public struct MuVec2
|
||||
@ -364,7 +364,7 @@ namespace MicroUI
|
||||
|
||||
public class MuStyle
|
||||
{
|
||||
public object? Font { get; set; } // Replace 'object' with actual font type as needed
|
||||
public object? Font { get; set; }
|
||||
public MuVec2 Size { get; set; }
|
||||
public int Padding { get; set; }
|
||||
public int Spacing { get; set; }
|
||||
@ -386,16 +386,13 @@ namespace MicroUI
|
||||
|
||||
public class MuContext
|
||||
{
|
||||
// Callbacks
|
||||
public TextWidthDelegate? TextWidth;
|
||||
public TextWidthDelegate? TextWidth;
|
||||
public TextHeightDelegate? TextHeight;
|
||||
public DrawFrameDelegate? DrawFrame;
|
||||
|
||||
// Styles
|
||||
public MuStyle Style { get; set; } = new MuStyle();
|
||||
|
||||
// IDs and last widget info
|
||||
public mu_Id Hover { get; set; } // assuming mu_Id is uint
|
||||
public mu_Id Hover { get; set; }
|
||||
public mu_Id Focus { get; set; }
|
||||
public mu_Id LastId { get; set; }
|
||||
public MuRect LastRect { get; set; }
|
||||
@ -403,16 +400,13 @@ namespace MicroUI
|
||||
public int UpdatedFocus { get; set; }
|
||||
public int Frame { get; set; }
|
||||
|
||||
// Containers
|
||||
public MuContainer? HoverRoot { get; set; }
|
||||
public MuContainer? NextHoverRoot { get; set; }
|
||||
public MuContainer? ScrollTarget { get; set; }
|
||||
|
||||
// Number edit buffer
|
||||
private char[] numberEditBuf = new char[Constants.MaxFormatLength]; // e.g. 127 or 128
|
||||
public mu_Id NumberEdit { get; set; }
|
||||
|
||||
// Stacks
|
||||
public string numberEditText = "";
|
||||
|
||||
public FixedStack<MuCommand> CommandList { get; } = new FixedStack<MuCommand>(Constants.CommandListSize);
|
||||
public FixedStack<MuContainer> RootList { get; } = new FixedStack<MuContainer>(Constants.RootListSize);
|
||||
public FixedStack<MuContainer> ContainerStack { get; } = new FixedStack<MuContainer>(Constants.ContainerStackSize);
|
||||
@ -420,12 +414,10 @@ namespace MicroUI
|
||||
public FixedStack<uint> IdStack { get; } = new FixedStack<uint>(Constants.IdStackSize);
|
||||
public FixedStack<MuLayout> LayoutStack { get; } = new FixedStack<MuLayout>(Constants.LayoutStackSize);
|
||||
|
||||
// Retained State Pools
|
||||
public MuPoolItem[] ContainerPool { get; } = new MuPoolItem[Constants.ContainerPoolSize];
|
||||
public MuContainer[] Containers { get; } = new MuContainer[Constants.ContainerPoolSize];
|
||||
public MuPoolItem[] TreeNodePool { get; } = new MuPoolItem[Constants.TreeNodePoolSize];
|
||||
|
||||
// Input State
|
||||
|
||||
public MuVec2 MousePos { get; set; }
|
||||
public MuVec2 LastMousePos { get; set; }
|
||||
public MuVec2 MouseDelta { get; set; }
|
||||
@ -434,7 +426,7 @@ namespace MicroUI
|
||||
public int MousePressed { get; set; }
|
||||
public int KeyDown { get; set; }
|
||||
public int KeyPressed { get; set; }
|
||||
public char[] inputText = new char[32];
|
||||
public string inputText = "";
|
||||
}
|
||||
|
||||
public static class MuAssert
|
||||
@ -473,20 +465,20 @@ namespace MicroUI
|
||||
ThumbSize = 8,
|
||||
Colors = new MuColor[]
|
||||
{
|
||||
new MuColor(230, 230, 230, 255), // MU_COLOR_TEXT
|
||||
new MuColor(25, 25, 25, 255), // MU_COLOR_BORDER
|
||||
new MuColor(50, 50, 50, 255), // MU_COLOR_WINDOWBG
|
||||
new MuColor(25, 25, 25, 255), // MU_COLOR_TITLEBG
|
||||
new MuColor(240, 240, 240, 255), // MU_COLOR_TITLETEXT
|
||||
new MuColor(0, 0, 0, 0), // MU_COLOR_PANELBG
|
||||
new MuColor(75, 75, 75, 255), // MU_COLOR_BUTTON
|
||||
new MuColor(95, 95, 95, 255), // MU_COLOR_BUTTONHOVER
|
||||
new MuColor(115, 115, 115, 255), // MU_COLOR_BUTTONFOCUS
|
||||
new MuColor(30, 30, 30, 255), // MU_COLOR_BASE
|
||||
new MuColor(35, 35, 35, 255), // MU_COLOR_BASEHOVER
|
||||
new MuColor(40, 40, 40, 255), // MU_COLOR_BASEFOCUS
|
||||
new MuColor(43, 43, 43, 255), // MU_COLOR_SCROLLBASE
|
||||
new MuColor(30, 30, 30, 255) // MU_COLOR_SCROLLTHUMB
|
||||
new MuColor(230, 230, 230, 255),
|
||||
new MuColor(25, 25, 25, 255),
|
||||
new MuColor(50, 50, 50, 255),
|
||||
new MuColor(25, 25, 25, 255),
|
||||
new MuColor(240, 240, 240, 255),
|
||||
new MuColor(0, 0, 0, 0),
|
||||
new MuColor(75, 75, 75, 255),
|
||||
new MuColor(95, 95, 95, 255),
|
||||
new MuColor(115, 115, 115, 255),
|
||||
new MuColor(30, 30, 30, 255),
|
||||
new MuColor(35, 35, 35, 255),
|
||||
new MuColor(40, 40, 40, 255),
|
||||
new MuColor(43, 43, 43, 255),
|
||||
new MuColor(30, 30, 30, 255)
|
||||
}
|
||||
};
|
||||
|
||||
@ -521,13 +513,10 @@ namespace MicroUI
|
||||
|
||||
public static void DrawFrame(MuContext ctx, MuRect rect, ColorType colorId)
|
||||
{
|
||||
// Clamp color ID to prevent index out of range
|
||||
int colorIndex = MathUtil.Clamp((int)colorId, 0, (int)ColorType.Max - 1);
|
||||
|
||||
// Draw filled rectangle with given color
|
||||
MuCommandList.DrawRect(ctx, rect, ctx.Style.Colors[colorIndex]);
|
||||
|
||||
// Early return for certain color IDs (skip border)
|
||||
if (colorId == ColorType.ScrollBase ||
|
||||
colorId == ColorType.ScrollThumb ||
|
||||
colorId == ColorType.TitleBg)
|
||||
@ -535,7 +524,6 @@ namespace MicroUI
|
||||
return;
|
||||
}
|
||||
|
||||
// Draw border if alpha > 0
|
||||
if (ctx.Style.Colors[(int)ColorType.Border].A > 0)
|
||||
{
|
||||
MuCommandList.DrawBox(ctx, ExpandRect(rect, 1), ctx.Style.Colors[(int)ColorType.Border]);
|
||||
@ -544,21 +532,16 @@ namespace MicroUI
|
||||
|
||||
public static void Init(MuContext ctx)
|
||||
{
|
||||
// Zeroing is not needed — C# classes are automatically zeroed/null-initialized.
|
||||
|
||||
// Assign the draw function delegate
|
||||
ctx.DrawFrame = DrawFrame;
|
||||
|
||||
// Copy the default style (make sure it's cloned, not shared!)
|
||||
ctx.Style = DefaultStyle;
|
||||
|
||||
// Initialize containers array with actual MuContainer objects
|
||||
for (int i = 0; i < ctx.Containers.Length; i++)
|
||||
{
|
||||
ctx.Containers[i] = new MuContainer();
|
||||
}
|
||||
|
||||
// Initialize container pool items
|
||||
for (int i = 0; i < ctx.ContainerPool.Length; i++)
|
||||
{
|
||||
ctx.ContainerPool[i] = new MuPoolItem(0, 0);
|
||||
@ -616,7 +599,7 @@ namespace MicroUI
|
||||
}
|
||||
|
||||
ctx.KeyPressed = 0;
|
||||
ctx.inputText[0] = '\0';
|
||||
ctx.inputText = "";
|
||||
ctx.MousePressed = 0;
|
||||
ctx.ScrollDelta = new MuVec2(0, 0);
|
||||
ctx.LastMousePos = ctx.MousePos;
|
||||
@ -636,13 +619,11 @@ namespace MicroUI
|
||||
else
|
||||
{
|
||||
var prev = ctx.RootList.Items[i - 1];
|
||||
// Set previous container's tail jump destination to current container's head + 1
|
||||
((MuJumpCommand)ctx.CommandList.Items[prev.TailIndex]).DestinationIndex = cnt.HeadIndex + 1;
|
||||
}
|
||||
|
||||
if (i == n - 1)
|
||||
{
|
||||
// Set last container's tail jump to the end of the command list
|
||||
((MuJumpCommand)ctx.CommandList.Items[cnt.TailIndex]).DestinationIndex = ctx.CommandList.Index;
|
||||
}
|
||||
}
|
||||
@ -707,42 +688,35 @@ namespace MicroUI
|
||||
{
|
||||
MuRect cr = GetClipRect(ctx);
|
||||
|
||||
// Completely outside clip rect
|
||||
if (r.X > cr.X + cr.W || r.X + r.W < cr.X ||
|
||||
r.Y > cr.Y + cr.H || r.Y + r.H < cr.Y)
|
||||
{
|
||||
return ClipMode.All; // MU_CLIP_ALL
|
||||
return ClipMode.All;
|
||||
}
|
||||
|
||||
// Completely inside clip rect
|
||||
if (r.X >= cr.X && r.X + r.W <= cr.X + cr.W &&
|
||||
r.Y >= cr.Y && r.Y + r.H <= cr.Y + cr.H)
|
||||
{
|
||||
return 0; // no clipping
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Partially clipped
|
||||
return ClipMode.Part; // MU_CLIP_PART
|
||||
return ClipMode.Part;
|
||||
}
|
||||
|
||||
public static void PushLayout(MuContext ctx, MuRect body, MuVec2 scroll)
|
||||
{
|
||||
MuLayout layout = new MuLayout();
|
||||
|
||||
// Adjust body position by subtracting scroll offset
|
||||
layout.Body = new MuRect(
|
||||
body.X - scroll.X,
|
||||
body.Y - scroll.Y,
|
||||
body.W,
|
||||
body.H);
|
||||
|
||||
// Initialize max to very negative values (like C's -0x1000000)
|
||||
layout.Max = new MuVec2(-0x1000000, -0x1000000);
|
||||
|
||||
// Push the layout struct onto the layout stack
|
||||
ctx.LayoutStack.Push(layout);
|
||||
|
||||
// Call mu_layout_row with count=1, widths pointer to width var, height=0
|
||||
int[] widths = { 0 };
|
||||
MuLayoutUtil.LayoutRow(ctx, 1, widths, 0);
|
||||
}
|
||||
@ -765,7 +739,6 @@ namespace MicroUI
|
||||
layout.Max.Y - layout.Body.Y
|
||||
);
|
||||
|
||||
// Pop container, layout, and id
|
||||
ctx.ContainerStack.Pop();
|
||||
ctx.LayoutStack.Pop();
|
||||
PopId(ctx);
|
||||
@ -786,7 +759,6 @@ namespace MicroUI
|
||||
|
||||
public static MuContainer? GetContainer(MuContext ctx, uint id, int opt)
|
||||
{
|
||||
// Try to get existing container from pool
|
||||
int idx = MuPool.Get(ctx, ctx.ContainerPool, id);
|
||||
if (idx >= 0)
|
||||
{
|
||||
@ -797,17 +769,14 @@ namespace MicroUI
|
||||
return ctx.Containers[idx];
|
||||
}
|
||||
|
||||
// If we're looking for a closed container and it doesn't exist, return null
|
||||
if ((opt & (int)Options.Closed) != 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Container not found in pool: init new container
|
||||
idx = MuPool.Init(ctx, ctx.ContainerPool, id);
|
||||
var cnt = ctx.Containers[idx];
|
||||
|
||||
// Reset all fields (equivalent to memset(cnt, 0, sizeof(*cnt)))
|
||||
cnt.HeadIndex = -1;
|
||||
cnt.TailIndex = -1;
|
||||
cnt.Rect = new MuRect(0, 0, 0, 0);
|
||||
@ -845,7 +814,6 @@ namespace MicroUI
|
||||
{
|
||||
int n = -1;
|
||||
int f = ctx.Frame;
|
||||
// Find the item with the oldest last_update
|
||||
for (int i = 0; i < items.Length; i++)
|
||||
{
|
||||
if (items[i].LastUpdate < f)
|
||||
@ -904,21 +872,7 @@ namespace MicroUI
|
||||
|
||||
public static void InputText(MuContext ctx, string text)
|
||||
{
|
||||
// Find the current length of text in the buffer (up to first null terminator)
|
||||
int len = 0;
|
||||
while (len < ctx.inputText.Length && ctx.inputText[len] != '\0')
|
||||
len++;
|
||||
|
||||
int size = text.Length;
|
||||
if (len + size + 1 > ctx.inputText.Length) // +1 for null terminator
|
||||
throw new Exception("Input text buffer overflow");
|
||||
|
||||
// Copy text into the buffer at the current position
|
||||
for (int i = 0; i < size && (len + i) < ctx.inputText.Length - 1; i++)
|
||||
ctx.inputText[len + i] = text[i];
|
||||
|
||||
// Null-terminate
|
||||
ctx.inputText[len + size] = '\0';
|
||||
ctx.inputText += text;
|
||||
}
|
||||
}
|
||||
|
||||
@ -939,16 +893,14 @@ namespace MicroUI
|
||||
var cmd = commands[index];
|
||||
if (cmd is MuJumpCommand jump)
|
||||
{
|
||||
// Jump to the destination index
|
||||
if (jump.DestinationIndex < 0 || jump.DestinationIndex >= count)
|
||||
return null; // Invalid jump, end iteration
|
||||
return null;
|
||||
index = jump.DestinationIndex;
|
||||
continue;
|
||||
}
|
||||
// Return the current command and advance index
|
||||
return commands[index++];
|
||||
}
|
||||
return null; // End of command list
|
||||
return null;
|
||||
}
|
||||
|
||||
public static MuJumpCommand PushJump(MuContext ctx, int destinationIndex = -1)
|
||||
@ -965,7 +917,6 @@ namespace MicroUI
|
||||
|
||||
public static void DrawRect(MuContext ctx, MuRect rect, MuColor color)
|
||||
{
|
||||
// Intersect with current clip rect
|
||||
rect = MicroUI.IntersectRects(rect, MicroUI.GetClipRect(ctx));
|
||||
if (rect.W > 0 && rect.H > 0)
|
||||
{
|
||||
@ -992,10 +943,8 @@ namespace MicroUI
|
||||
if (clipped == ClipMode.All) return;
|
||||
if (clipped == ClipMode.Part) SetClip(ctx, MicroUI.GetClipRect(ctx));
|
||||
|
||||
// Add command
|
||||
MuCommandList.Push(ctx, new MuTextCommand(font, pos, color, str));
|
||||
|
||||
// Reset clipping if it was set
|
||||
if (clipped != 0) SetClip(ctx, MicroUI.UnclippedRect);
|
||||
}
|
||||
|
||||
@ -1011,7 +960,6 @@ namespace MicroUI
|
||||
}
|
||||
}
|
||||
|
||||
// Layout next type enum (matches C enum { RELATIVE = 1, ABSOLUTE = 2 })
|
||||
enum LayoutNextType
|
||||
{
|
||||
Relative = 1,
|
||||
@ -1028,10 +976,8 @@ namespace MicroUI
|
||||
|
||||
public static void LayoutEndColumn(MuContext ctx)
|
||||
{
|
||||
// Get the child layout (top of stack)
|
||||
ref var b = ref MicroUI.GetLayout(ctx);
|
||||
ctx.LayoutStack.Pop();
|
||||
// Get the parent layout (now top of stack)
|
||||
ref var a = ref MicroUI.GetLayout(ctx);
|
||||
|
||||
a.Position = new MuVec2(
|
||||
@ -1056,7 +1002,7 @@ namespace MicroUI
|
||||
}
|
||||
layout.Items = items;
|
||||
layout.Position = new MuVec2(layout.Indent, layout.NextRow);
|
||||
layout.Size = new MuVec2(layout.Size.X, height); // Only Y is updated
|
||||
layout.Size = new MuVec2(layout.Size.X, height);
|
||||
layout.ItemIndex = 0;
|
||||
}
|
||||
|
||||
@ -1098,17 +1044,14 @@ namespace MicroUI
|
||||
}
|
||||
else
|
||||
{
|
||||
// handle next row
|
||||
if (layout.ItemIndex == layout.Items)
|
||||
{
|
||||
LayoutRow(ctx, layout.Items, null, layout.Size.Y);
|
||||
}
|
||||
|
||||
// position
|
||||
res.X = layout.Position.X;
|
||||
res.Y = layout.Position.Y;
|
||||
|
||||
// size
|
||||
res.W = layout.Items > 0 ? layout.Widths[layout.ItemIndex] : layout.Size.X;
|
||||
res.H = layout.Size.Y;
|
||||
if (res.W == 0) res.W = style.Size.X + style.Padding * 2;
|
||||
@ -1119,18 +1062,15 @@ namespace MicroUI
|
||||
layout.ItemIndex++;
|
||||
}
|
||||
|
||||
// update position
|
||||
layout.Position = new MuVec2(
|
||||
layout.Position.X + res.W + style.Spacing,
|
||||
layout.Position.Y
|
||||
);
|
||||
layout.NextRow = MathUtil.Max(layout.NextRow, res.Y + res.H + style.Spacing);
|
||||
|
||||
// apply body offset
|
||||
res.X += layout.Body.X;
|
||||
res.Y += layout.Body.Y;
|
||||
|
||||
// update max position
|
||||
layout.Max = new MuVec2(
|
||||
MathUtil.Max(layout.Max.X, res.X + res.W),
|
||||
MathUtil.Max(layout.Max.Y, res.Y + res.H)
|
||||
@ -1146,52 +1086,37 @@ namespace MicroUI
|
||||
|
||||
public static void PushContainerBody(MuContext ctx, MuContainer cnt, MuRect body, int opt)
|
||||
{
|
||||
// If scrolling is enabled, handle scrollbars (stub for now)
|
||||
if ((opt & (int)Options.NoScroll) == 0)
|
||||
{
|
||||
// TODO: Implement scrollbars(ctx, cnt, ref body);
|
||||
}
|
||||
|
||||
// Push layout for the container body, with padding and scroll offset
|
||||
MicroUI.PushLayout(ctx, MicroUI.ExpandRect(body, -ctx.Style.Padding), cnt.Scroll);
|
||||
|
||||
// Store the body rect in the container
|
||||
cnt.Body = body;
|
||||
}
|
||||
|
||||
public static void BeginRootContainer(MuContext ctx, MuContainer cnt)
|
||||
{
|
||||
// Push container onto container stack
|
||||
ctx.ContainerStack.Push(cnt);
|
||||
|
||||
// Push container to roots list and push head command
|
||||
ctx.RootList.Push(cnt);
|
||||
cnt.HeadIndex = ctx.CommandList.Index; // Store the current command index as head
|
||||
MuCommandList.PushJump(ctx); // Push a jump command (will be set up later)
|
||||
cnt.HeadIndex = ctx.CommandList.Index;
|
||||
MuCommandList.PushJump(ctx);
|
||||
|
||||
// Set as hover root if the mouse is overlapping this container and it has a
|
||||
// higher zindex than the current hover root
|
||||
if (MicroUI.RectOverlapsVec2(cnt.Rect, ctx.MousePos) &&
|
||||
(ctx.NextHoverRoot == null || cnt.ZIndex > ctx.NextHoverRoot.ZIndex))
|
||||
{
|
||||
ctx.NextHoverRoot = cnt;
|
||||
}
|
||||
|
||||
// Clipping is reset here in case a root-container is made within
|
||||
// another root-container's begin/end block; this prevents the inner
|
||||
// root-container being clipped to the outer
|
||||
MicroUI.PushClipRect(ctx, MicroUI.UnclippedRect);
|
||||
}
|
||||
public static void EndRootContainer(MuContext ctx)
|
||||
{
|
||||
// Push tail 'goto' jump command and set head 'skip' command. The final steps
|
||||
// on setting up these are done in MicroUI.End()
|
||||
MuContainer cnt = MicroUI.GetCurrentContainer(ctx);
|
||||
cnt.TailIndex = ctx.CommandList.Index; // Store the current command index as tail
|
||||
MuCommandList.PushJump(ctx); // Push a jump command (will be set up later)
|
||||
cnt.TailIndex = ctx.CommandList.Index;
|
||||
MuCommandList.PushJump(ctx);
|
||||
|
||||
// Set the head jump command to point to the current command index
|
||||
// (This will be finalized in MicroUI.End())
|
||||
if (cnt.HeadIndex >= 0 && cnt.HeadIndex < ctx.CommandList.Index)
|
||||
{
|
||||
var headJump = ctx.CommandList.Items[cnt.HeadIndex] as MuJumpCommand;
|
||||
@ -1201,47 +1126,38 @@ namespace MicroUI
|
||||
}
|
||||
}
|
||||
|
||||
// Pop base clip rect and container
|
||||
MicroUI.PopClipRect(ctx);
|
||||
MicroUI.PopContainer(ctx);
|
||||
}
|
||||
public static bool BeginWindowEx(MuContext ctx, string title, MuRect rect, int opt)
|
||||
{
|
||||
// 1. Get/Init Container
|
||||
uint id = MicroUI.GetId(ctx, System.Text.Encoding.UTF8.GetBytes(title));
|
||||
MuContainer? cnt = MicroUI.GetContainer(ctx, id, opt);
|
||||
if (cnt == null || !cnt.Open) return false;
|
||||
|
||||
// 2. Push ID
|
||||
MicroUI.PushId(ctx, System.Text.Encoding.UTF8.GetBytes(title));
|
||||
|
||||
// 3. Set Initial Rect
|
||||
if (cnt.Rect.W == 0) cnt.Rect = rect;
|
||||
|
||||
// 4. Begin Root Container
|
||||
MuControl.BeginRootContainer(ctx, cnt);
|
||||
rect = cnt.Rect;
|
||||
var body = rect;
|
||||
|
||||
// 5. Draw Window Frame
|
||||
if ((opt & (int)Options.NoFrame) == 0)
|
||||
{
|
||||
ctx.DrawFrame?.Invoke(ctx, rect, ColorType.WindowBg);
|
||||
}
|
||||
|
||||
// 6. Draw Title Bar
|
||||
if ((opt & (int)Options.NoTitle) == 0)
|
||||
{
|
||||
var tr = rect;
|
||||
tr.H = ctx.Style.TitleHeight;
|
||||
ctx.DrawFrame?.Invoke(ctx, tr, ColorType.TitleBg);
|
||||
|
||||
// Title text and drag
|
||||
uint titleId = MicroUI.GetId(ctx, System.Text.Encoding.UTF8.GetBytes("!title"));
|
||||
MuControl.UpdateControl(ctx, titleId, tr, opt);
|
||||
MuControl.DrawControlText(ctx, title, tr, ColorType.TitleText, opt);
|
||||
|
||||
// Move window if dragging title bar
|
||||
if (titleId == ctx.Focus && (ctx.MouseDown & (int)MouseButton.Left) != 0)
|
||||
{
|
||||
cnt.Rect = new MuRect(
|
||||
@ -1252,11 +1168,9 @@ namespace MicroUI
|
||||
);
|
||||
}
|
||||
|
||||
// Adjust body for title bar
|
||||
body.Y += tr.H;
|
||||
body.H -= tr.H;
|
||||
|
||||
// Close button
|
||||
if ((opt & (int)Options.NoClose) == 0)
|
||||
{
|
||||
uint closeId = MicroUI.GetId(ctx, System.Text.Encoding.UTF8.GetBytes("!close"));
|
||||
@ -1271,24 +1185,19 @@ namespace MicroUI
|
||||
}
|
||||
}
|
||||
|
||||
// 7. Push Container Body Layout
|
||||
MuControl.PushContainerBody(ctx, cnt, body, opt); // Implement or comment out
|
||||
MuControl.PushContainerBody(ctx, cnt, body, opt);
|
||||
|
||||
// 8. Resize handle
|
||||
if ((opt & (int)Options.NoResize) == 0)
|
||||
{
|
||||
int sz = ctx.Style.TitleHeight;
|
||||
uint resizeId = MicroUI.GetId(ctx, System.Text.Encoding.UTF8.GetBytes("!resize"));
|
||||
var r = new MuRect(rect.X + rect.W - sz, rect.Y + rect.H - sz, sz, sz);
|
||||
MuControl.UpdateControl(ctx, resizeId, r, opt);
|
||||
// Chevron/arrow design for resize handle
|
||||
int pad = 4;
|
||||
var baseColor = ctx.Style.Colors[(int)ColorType.Base];
|
||||
// Horizontal bar (bottom edge)
|
||||
MuCommandList.Push(ctx, new MuRectCommand(
|
||||
new MuRect(r.X + r.W - pad - 8, r.Y + r.H - pad - 2, 8, 2), baseColor));
|
||||
|
||||
// Vertical bar (right edge)
|
||||
MuCommandList.Push(ctx, new MuRectCommand(
|
||||
new MuRect(r.X + r.W - pad - 2, r.Y + r.H - pad - 8, 2, 8), baseColor));
|
||||
if (resizeId == ctx.Focus && (ctx.MouseDown & (int)MouseButton.Left) != 0)
|
||||
@ -1302,7 +1211,6 @@ namespace MicroUI
|
||||
}
|
||||
}
|
||||
|
||||
// 9. Auto-size
|
||||
if ((opt & (int)Options.AutoSize) != 0)
|
||||
{
|
||||
var r = MicroUI.GetLayout(ctx).Body;
|
||||
@ -1314,16 +1222,13 @@ namespace MicroUI
|
||||
);
|
||||
}
|
||||
|
||||
// 10. Popup close
|
||||
if ((opt & (int)Options.Popup) != 0 && ctx.MousePressed != 0 && ctx.HoverRoot != cnt)
|
||||
{
|
||||
cnt.Open = false;
|
||||
}
|
||||
|
||||
// 11. Push Clip Rect
|
||||
MicroUI.PushClipRect(ctx, cnt.Body);
|
||||
|
||||
// 12. Return Active
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1333,21 +1238,18 @@ namespace MicroUI
|
||||
MuControl.EndRootContainer(ctx);
|
||||
}
|
||||
|
||||
// Helper functions for controls
|
||||
public static void DrawControlFrame(MuContext ctx, uint id, MuRect rect, ColorType colorId, int opt)
|
||||
{
|
||||
if ((opt & (int)Options.NoFrame) != 0) { return; }
|
||||
|
||||
// Adjust color based on state: normal, hover, focus
|
||||
if (ctx.Focus == id)
|
||||
{
|
||||
colorId += 2; // Focus state
|
||||
colorId += 2;
|
||||
}
|
||||
else if (ctx.Hover == id)
|
||||
{
|
||||
colorId += 1; // Hover state
|
||||
colorId += 1;
|
||||
}
|
||||
// else: normal state (colorId unchanged)
|
||||
|
||||
ctx.DrawFrame?.Invoke(ctx, rect, colorId);
|
||||
}
|
||||
@ -1391,7 +1293,6 @@ namespace MicroUI
|
||||
|
||||
private static bool InHoverRoot(MuContext ctx)
|
||||
{
|
||||
// Check if we're in the hover root container
|
||||
return ctx.HoverRoot == null || ctx.HoverRoot == MicroUI.GetCurrentContainer(ctx);
|
||||
}
|
||||
|
||||
@ -1439,13 +1340,11 @@ namespace MicroUI
|
||||
MuRect r = MuLayoutUtil.LayoutNext(ctx);
|
||||
UpdateControl(ctx, id, r, opt);
|
||||
|
||||
// Handle click
|
||||
if ((ctx.MousePressed & (int)MouseButton.Left) != 0 && ctx.Focus == id)
|
||||
{
|
||||
res |= ResultFlags.Submit;
|
||||
}
|
||||
|
||||
// Draw
|
||||
DrawControlFrame(ctx, id, r, ColorType.Button, opt);
|
||||
if (!string.IsNullOrEmpty(label))
|
||||
{
|
||||
@ -1464,7 +1363,6 @@ namespace MicroUI
|
||||
ResultFlags res = 0;
|
||||
uint id;
|
||||
|
||||
// Create ID that includes both label and state
|
||||
if (!string.IsNullOrEmpty(label))
|
||||
{
|
||||
var idData = System.Text.Encoding.UTF8.GetBytes(label + state.ToString());
|
||||
@ -1478,14 +1376,12 @@ namespace MicroUI
|
||||
MuRect r = MuLayoutUtil.LayoutNext(ctx);
|
||||
UpdateControl(ctx, id, r, 0);
|
||||
|
||||
// Handle click
|
||||
if ((ctx.MousePressed & (int)MouseButton.Left) != 0 && ctx.Focus == id)
|
||||
{
|
||||
state = !state;
|
||||
res |= ResultFlags.Change;
|
||||
}
|
||||
|
||||
// Draw checkbox box
|
||||
var box = new MuRect(r.X, r.Y, r.H, r.H);
|
||||
DrawControlFrame(ctx, id, box, ColorType.Base, 0);
|
||||
|
||||
@ -1494,7 +1390,6 @@ namespace MicroUI
|
||||
MuCommandList.DrawIcon(ctx, (int)IconType.Check, box, ctx.Style.Colors[(int)ColorType.Text]);
|
||||
}
|
||||
|
||||
// Draw label
|
||||
if (!string.IsNullOrEmpty(label))
|
||||
{
|
||||
var labelRect = new MuRect(r.X + box.W, r.Y, r.W - box.W, r.H);
|
||||
@ -1546,33 +1441,23 @@ namespace MicroUI
|
||||
DrawControlText(ctx, text, r, ColorType.Text, 0);
|
||||
}
|
||||
|
||||
// Helper method for number textbox functionality
|
||||
private static bool NumberTextbox(MuContext ctx, ref float value, MuRect r, uint id)
|
||||
{
|
||||
// Check if we should enter text input mode (Shift+Click)
|
||||
if ((ctx.MousePressed & (int)MouseButton.Left) != 0 &&
|
||||
(ctx.KeyDown & (int)KeyModifiers.Shift) != 0 &&
|
||||
ctx.Hover == id)
|
||||
{
|
||||
ctx.NumberEdit = id;
|
||||
// Convert number to string for editing using the same format as C version
|
||||
var numberStr = value.ToString("G3"); // MU_REAL_FMT is "%.3g"
|
||||
// Copy to input buffer (simplified - in real implementation you'd need a proper buffer)
|
||||
for (int i = 0; i < Math.Min(numberStr.Length, ctx.inputText.Length); i++)
|
||||
{
|
||||
ctx.inputText[i] = numberStr[i];
|
||||
}
|
||||
ctx.numberEditText = value.ToString("G3");
|
||||
}
|
||||
|
||||
if (ctx.NumberEdit == id)
|
||||
{
|
||||
// For now, we'll implement a simplified textbox
|
||||
// In a full implementation, you'd use TextboxRaw here
|
||||
var result = TextboxRaw(ctx, ctx.inputText, ctx.inputText.Length, id, r, 0);
|
||||
var result = TextboxRaw(ctx, ref ctx.numberEditText, id, r, 0);
|
||||
|
||||
if ((result & ResultFlags.Submit) != 0 || ctx.Focus != id)
|
||||
{
|
||||
// Parse the number back
|
||||
if (float.TryParse(new string(ctx.inputText).Trim('\0'), out float newValue))
|
||||
if (float.TryParse(ctx.numberEditText, out float newValue))
|
||||
{
|
||||
value = newValue;
|
||||
}
|
||||
@ -1580,51 +1465,31 @@ namespace MicroUI
|
||||
}
|
||||
else
|
||||
{
|
||||
return true; // Still in text input mode
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static MuResult TextboxRaw(MuContext ctx, char[] buf, int bufSize, uint id, MuRect r, int opt)
|
||||
public static MuResult TextboxRaw(MuContext ctx, ref string value, uint id, MuRect r, int opt)
|
||||
{
|
||||
ResultFlags res = 0;
|
||||
UpdateControl(ctx, id, r, opt | (int)Options.HoldFocus);
|
||||
|
||||
if (ctx.Focus == id)
|
||||
{
|
||||
// Handle text input
|
||||
int len = 0;
|
||||
while (len < bufSize && buf[len] != '\0') len++;
|
||||
|
||||
// Get actual length of text in input buffer (up to first null terminator)
|
||||
int inputLen = 0;
|
||||
while (inputLen < ctx.inputText.Length && ctx.inputText[inputLen] != '\0') inputLen++;
|
||||
|
||||
int n = Math.Min(bufSize - len - 1, inputLen);
|
||||
if (n > 0)
|
||||
if (ctx.inputText.Length > 0)
|
||||
{
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
if (len + i < bufSize)
|
||||
buf[len + i] = ctx.inputText[i];
|
||||
}
|
||||
len += n;
|
||||
if (len < bufSize) buf[len] = '\0';
|
||||
value += ctx.inputText;
|
||||
res |= ResultFlags.Change;
|
||||
}
|
||||
|
||||
// Handle backspace
|
||||
if ((ctx.KeyPressed & (int)KeyModifiers.Backspace) != 0 && len > 0)
|
||||
if ((ctx.KeyPressed & (int)KeyModifiers.Backspace) != 0 && value.Length > 0)
|
||||
{
|
||||
// Skip UTF-8 continuation bytes (simplified for C#)
|
||||
while (len > 0 && (buf[len - 1] & 0xC0) == 0x80) len--;
|
||||
if (len > 0) len--;
|
||||
buf[len] = '\0';
|
||||
value = value.Length > 0 ? value.Substring(0, value.Length - 1) : "";
|
||||
res |= ResultFlags.Change;
|
||||
}
|
||||
|
||||
// Handle return
|
||||
if ((ctx.KeyPressed & (int)KeyModifiers.Return) != 0)
|
||||
{
|
||||
MicroUI.SetFocus(ctx, 0);
|
||||
@ -1632,37 +1497,30 @@ namespace MicroUI
|
||||
}
|
||||
}
|
||||
|
||||
// Draw
|
||||
DrawControlFrame(ctx, id, r, ColorType.Base, opt);
|
||||
string displayText = new string(buf).Trim('\0');
|
||||
DrawControlText(ctx, displayText, r, ColorType.Text, opt);
|
||||
DrawControlText(ctx, value, r, ColorType.Text, opt);
|
||||
|
||||
return new MuResult(res);
|
||||
}
|
||||
|
||||
public static MuResult SliderEx(MuContext ctx, string name, ref float value, float low, float high, float step, string format, int opt)
|
||||
{
|
||||
char[] buf = new char[Constants.MaxFormatLength + 1];
|
||||
MuRect thumb;
|
||||
int x, w;
|
||||
ResultFlags res = 0;
|
||||
float last = value, v = last;
|
||||
|
||||
// Generate ID from the name, just like BeginWindowEx does
|
||||
uint id = MicroUI.GetId(ctx, System.Text.Encoding.UTF8.GetBytes(name));
|
||||
|
||||
MuRect baseRect = MuLayoutUtil.LayoutNext(ctx);
|
||||
|
||||
// Handle text input mode
|
||||
if (NumberTextbox(ctx, ref v, baseRect, id))
|
||||
{
|
||||
return new MuResult(res);
|
||||
}
|
||||
|
||||
// Handle normal mode
|
||||
UpdateControl(ctx, id, baseRect, opt);
|
||||
|
||||
// Handle input - EXACTLY match C version logic
|
||||
if (ctx.Focus == id && (ctx.MouseDown | ctx.MousePressed) == (int)MouseButton.Left)
|
||||
{
|
||||
v = low + (ctx.MousePos.X - baseRect.X) * (high - low) / baseRect.W;
|
||||
@ -1672,61 +1530,48 @@ namespace MicroUI
|
||||
}
|
||||
}
|
||||
|
||||
// Clamp and store value, update res
|
||||
value = v = MathUtil.Clamp(v, low, high);
|
||||
if (last != v) { res |= ResultFlags.Change; }
|
||||
|
||||
// Draw base
|
||||
DrawControlFrame(ctx, id, baseRect, ColorType.Base, opt);
|
||||
|
||||
// Draw thumb
|
||||
w = ctx.Style.ThumbSize;
|
||||
x = (int)((v - low) * (baseRect.W - w) / (high - low));
|
||||
thumb = new MuRect(baseRect.X + x, baseRect.Y, w, baseRect.H);
|
||||
DrawControlFrame(ctx, id, thumb, ColorType.Button, opt);
|
||||
|
||||
// Draw text
|
||||
string text = v.ToString(format);
|
||||
DrawControlText(ctx, text, baseRect, ColorType.Text, opt);
|
||||
|
||||
return new MuResult(res);
|
||||
}
|
||||
|
||||
// Remove the caller information overload since we're using explicit names now
|
||||
|
||||
public static MuResult NumberEx(MuContext ctx, string name, ref float value, float step, string format, int opt)
|
||||
{
|
||||
char[] buf = new char[Constants.MaxFormatLength + 1];
|
||||
ResultFlags res = 0;
|
||||
|
||||
// Generate ID from the name, just like BeginWindowEx does
|
||||
uint id = MicroUI.GetId(ctx, System.Text.Encoding.UTF8.GetBytes(name));
|
||||
|
||||
MuRect baseRect = MuLayoutUtil.LayoutNext(ctx);
|
||||
float last = value;
|
||||
|
||||
// Handle text input mode
|
||||
if (NumberTextbox(ctx, ref value, baseRect, id))
|
||||
{
|
||||
return new MuResult(res);
|
||||
}
|
||||
|
||||
// Handle normal mode
|
||||
UpdateControl(ctx, id, baseRect, opt);
|
||||
|
||||
// Handle input - EXACTLY match C version logic
|
||||
if (ctx.Focus == id && ctx.MouseDown == (int)MouseButton.Left)
|
||||
{
|
||||
value += ctx.MouseDelta.X * step;
|
||||
}
|
||||
|
||||
// Set flag if value changed
|
||||
if (value != last) { res |= ResultFlags.Change; }
|
||||
|
||||
// Draw base
|
||||
DrawControlFrame(ctx, id, baseRect, ColorType.Base, opt);
|
||||
|
||||
// Draw text
|
||||
string text = value.ToString(format);
|
||||
DrawControlText(ctx, text, baseRect, ColorType.Text, opt);
|
||||
|
||||
|
||||
@ -8,9 +8,10 @@ class Program
|
||||
{
|
||||
// Key state tracking for key up events
|
||||
private static HashSet<int> pressedKeys = new HashSet<int>();
|
||||
// Persistent textbox buffer
|
||||
private static char[] textboxBuf = new char[32];
|
||||
private static bool textboxBufInitialized = false;
|
||||
// Persistent textbox value
|
||||
private static string textboxValue = "test";
|
||||
// Second number value for testing multiple number controls
|
||||
private static float secondValue = 25.0f;
|
||||
// Track focus changes
|
||||
private static uint lastFocus = 0;
|
||||
|
||||
@ -89,6 +90,16 @@ class Program
|
||||
}
|
||||
}
|
||||
|
||||
// Handle Shift key state (for Shift+Click functionality)
|
||||
if (Raylib.IsKeyDown(KeyboardKey.LeftShift) || Raylib.IsKeyDown(KeyboardKey.RightShift))
|
||||
{
|
||||
ctx.KeyDown |= (int)KeyModifiers.Shift;
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx.KeyDown &= ~(int)KeyModifiers.Shift;
|
||||
}
|
||||
|
||||
// Handle key up events for modifier keys
|
||||
var keysToRemove = new List<int>();
|
||||
foreach (int pressedKey in pressedKeys)
|
||||
@ -254,26 +265,36 @@ class Program
|
||||
{
|
||||
MuLayoutUtil.LayoutRow(ctx, 1, new int[] { 120 }, 0);
|
||||
float test = 0;
|
||||
var sliderResult = MuControl.SliderEx(ctx, "main_slider", ref sliderValue, 0.0f, 100.0f, 1.0f, "F1", 0);
|
||||
//var sliderResult = MuControl.SliderEx(ctx, "main_slider", ref sliderValue, 0.0f, 100.0f, 1.0f, "F1", 0);
|
||||
MuControl.SliderEx(ctx, "test_slider", ref test, 0.0f, 100.0f, 1.0f, "F1", 0);
|
||||
if ((sliderResult & ResultFlags.Change) != 0)
|
||||
{
|
||||
Console.WriteLine($"Slider value changed to: {sliderValue}");
|
||||
}
|
||||
// if ((sliderResult & ResultFlags.Change) != 0)
|
||||
// {
|
||||
// Console.WriteLine($"Slider value changed to: {sliderValue}");
|
||||
// }
|
||||
MuControl.Text(ctx, "Other controls here...");
|
||||
|
||||
// Test TextboxRaw
|
||||
if (!textboxBufInitialized) {
|
||||
string initial = "Edit me!";
|
||||
for (int i = 0; i < initial.Length && i < textboxBuf.Length; i++) textboxBuf[i] = initial[i];
|
||||
textboxBufInitialized = true;
|
||||
}
|
||||
var textboxRect = MuLayoutUtil.LayoutNext(ctx);
|
||||
var textboxResult = MuControl.TextboxRaw(ctx, textboxBuf, textboxBuf.Length, 12345, textboxRect, 0);
|
||||
var textboxResult = MuControl.TextboxRaw(ctx, ref textboxValue, 12345, textboxRect, 0);
|
||||
if ((textboxResult & ResultFlags.Change) != 0)
|
||||
{
|
||||
string value = new string(textboxBuf).TrimEnd('\0');
|
||||
Console.WriteLine($"Textbox changed: {value}");
|
||||
Console.WriteLine($"Textbox changed: {textboxValue}");
|
||||
}
|
||||
|
||||
// Test NumberEx (number textbox)
|
||||
MuControl.Text(ctx, "Number control (Shift+Click to edit):");
|
||||
var numberResult = MuControl.NumberEx(ctx, "test_number", ref sliderValue, 1.0f, "F2", 0);
|
||||
if ((numberResult & ResultFlags.Change) != 0)
|
||||
{
|
||||
Console.WriteLine($"Number changed to: {sliderValue}");
|
||||
}
|
||||
|
||||
// Test second NumberEx (number textbox)
|
||||
MuControl.Text(ctx, "Second number control (Shift+Click to edit):");
|
||||
var secondNumberResult = MuControl.NumberEx(ctx, "test_number2", ref secondValue, 0.5f, "F2", 0);
|
||||
if ((secondNumberResult & ResultFlags.Change) != 0)
|
||||
{
|
||||
Console.WriteLine($"Second number changed to: {secondValue}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -358,6 +358,12 @@ void window(mu_Context* ctx, float* value) {
|
||||
if (mu_textbox_raw(ctx, textbox_buf, sizeof(textbox_buf), 12345, textbox_rect, 0)) {
|
||||
printf("Textbox changed: %s\n", textbox_buf);
|
||||
}
|
||||
|
||||
// Test NumberEx (number textbox)
|
||||
mu_layout_row(ctx, 1, (int[]){120}, 0);
|
||||
if (mu_number_ex(ctx, value, 1.0f, "%.1f", 0) & MU_RES_SUBMIT) {
|
||||
printf("Number changed to: %.1f\n", *value);
|
||||
}
|
||||
}
|
||||
|
||||
// --- Right column ---
|
||||
|
||||
Loading…
Reference in New Issue
Block a user