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