First milestone: Getting windows drawing
Command list is working, windows draw in the correct order
This commit is contained in:
parent
d56f214a44
commit
deda09a4a5
@ -1,4 +1,5 @@
|
|||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
namespace MicroUI
|
namespace MicroUI
|
||||||
{
|
{
|
||||||
@ -37,7 +38,7 @@ namespace MicroUI
|
|||||||
public static float Clamp(float x, float a, float b) => Min(b, Max(a, x));
|
public static float Clamp(float x, float a, float b) => Min(b, Max(a, x));
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct FixedStack<T>
|
public class FixedStack<T>
|
||||||
{
|
{
|
||||||
public int Index;
|
public int Index;
|
||||||
public T[] Items;
|
public T[] Items;
|
||||||
@ -504,7 +505,7 @@ namespace MicroUI
|
|||||||
public static void DrawFrame(MuContext ctx, MuRect rect, ColorType colorId)
|
public static void DrawFrame(MuContext ctx, MuRect rect, ColorType colorId)
|
||||||
{
|
{
|
||||||
// Draw filled rectangle with given color
|
// Draw filled rectangle with given color
|
||||||
//DrawRect(ctx, rect, ctx.Style.Colors[(int)colorId]); // TODO: Implement DrawRect
|
MuCommandList.DrawRect(ctx, rect, ctx.Style.Colors[(int)colorId]);
|
||||||
|
|
||||||
// Early return for certain color IDs (skip border)
|
// Early return for certain color IDs (skip border)
|
||||||
if (colorId == ColorType.ScrollBase ||
|
if (colorId == ColorType.ScrollBase ||
|
||||||
@ -517,7 +518,7 @@ namespace MicroUI
|
|||||||
// Draw border if alpha > 0
|
// Draw border if alpha > 0
|
||||||
if (ctx.Style.Colors[(int)ColorType.Border].A > 0)
|
if (ctx.Style.Colors[(int)ColorType.Border].A > 0)
|
||||||
{
|
{
|
||||||
//DrawBox(ctx, ExpandRect(rect, 1), ctx.Style.Colors[(int)ColorType.Border]); // TODO: Implement DrawBox
|
MuCommandList.DrawBox(ctx, ExpandRect(rect, 1), ctx.Style.Colors[(int)ColorType.Border]); // TODO: Implement DrawBox
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -530,6 +531,18 @@ namespace MicroUI
|
|||||||
|
|
||||||
// Copy the default style (make sure it's cloned, not shared!)
|
// 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++)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Begin(MuContext ctx)
|
public static void Begin(MuContext ctx)
|
||||||
@ -579,7 +592,7 @@ namespace MicroUI
|
|||||||
ctx.NextHoverRoot.ZIndex < ctx.LastZIndex &&
|
ctx.NextHoverRoot.ZIndex < ctx.LastZIndex &&
|
||||||
ctx.NextHoverRoot.ZIndex >= 0)
|
ctx.NextHoverRoot.ZIndex >= 0)
|
||||||
{
|
{
|
||||||
//BringToFront(ctx.NextHoverRoot); // TODO: Implement BringToFront
|
BringToFront(ctx, ctx.NextHoverRoot); // TODO: Implement BringToFront
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.KeyPressed = 0;
|
ctx.KeyPressed = 0;
|
||||||
@ -651,8 +664,12 @@ namespace MicroUI
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void PushClipRect(MuContext ctx, MuRect rect) {
|
public static void PushClipRect(MuContext ctx, MuRect rect) {
|
||||||
MuRect last = GetClipRect(ctx);
|
if (ctx.ClipStack.Index == 0) {
|
||||||
ctx.ClipStack.Push( IntersectRects(rect, last));
|
ctx.ClipStack.Push(rect);
|
||||||
|
} else {
|
||||||
|
MuRect last = GetClipRect(ctx);
|
||||||
|
ctx.ClipStack.Push(IntersectRects(rect, last));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void PopClipRect(MuContext ctx)
|
public static void PopClipRect(MuContext ctx)
|
||||||
@ -707,10 +724,10 @@ namespace MicroUI
|
|||||||
|
|
||||||
// Call mu_layout_row with count=1, widths pointer to width var, height=0
|
// Call mu_layout_row with count=1, widths pointer to width var, height=0
|
||||||
int[] widths = { 0 };
|
int[] widths = { 0 };
|
||||||
LayoutRow(ctx, 1, widths, 0);
|
MuLayoutUtil.LayoutRow(ctx, 1, widths, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ref MuLayout GetLayout(MuContext ctx)
|
public static ref MuLayout GetLayout(MuContext ctx)
|
||||||
{
|
{
|
||||||
if (ctx.LayoutStack.Index == 0)
|
if (ctx.LayoutStack.Index == 0)
|
||||||
throw new InvalidOperationException("Layout stack is empty.");
|
throw new InvalidOperationException("Layout stack is empty.");
|
||||||
@ -718,7 +735,7 @@ namespace MicroUI
|
|||||||
return ref ctx.LayoutStack.Items[ctx.LayoutStack.Index - 1];
|
return ref ctx.LayoutStack.Items[ctx.LayoutStack.Index - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PopContainer(MuContext ctx)
|
public static void PopContainer(MuContext ctx)
|
||||||
{
|
{
|
||||||
MuContainer cnt = GetCurrentContainer(ctx);
|
MuContainer cnt = GetCurrentContainer(ctx);
|
||||||
MuLayout layout = GetLayout(ctx);
|
MuLayout layout = GetLayout(ctx);
|
||||||
@ -734,7 +751,7 @@ namespace MicroUI
|
|||||||
PopId(ctx);
|
PopId(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
static MuContainer GetCurrentContainer(MuContext ctx)
|
public static MuContainer GetCurrentContainer(MuContext ctx)
|
||||||
{
|
{
|
||||||
MuAssert.Expect(ctx.ContainerStack.Index > 0);
|
MuAssert.Expect(ctx.ContainerStack.Index > 0);
|
||||||
return ctx.ContainerStack.Items[ctx.ContainerStack.Index - 1];
|
return ctx.ContainerStack.Items[ctx.ContainerStack.Index - 1];
|
||||||
@ -745,46 +762,49 @@ namespace MicroUI
|
|||||||
**============================================================================*/
|
**============================================================================*/
|
||||||
|
|
||||||
|
|
||||||
public static void LayoutRow(MuContext ctx, int items, int[] widths, int height)
|
|
||||||
|
|
||||||
|
public static MuContainer? GetContainer(MuContext ctx, uint id, int opt)
|
||||||
{
|
{
|
||||||
var layout = GetLayout(ctx); // get current layout (implement accordingly)
|
// Try to get existing container from pool
|
||||||
|
int idx = MuPool.Get(ctx, ctx.ContainerPool, id);
|
||||||
if (items > Constants.MaxWidths)
|
|
||||||
throw new ArgumentOutOfRangeException(nameof(items), $"Items cannot be more than {Constants.MaxWidths}.");
|
|
||||||
|
|
||||||
// Copy widths into layout.Widths
|
|
||||||
Array.Copy(widths, layout.Widths, items);
|
|
||||||
|
|
||||||
layout.Items = items;
|
|
||||||
layout.Position = new MuVec2(layout.Indent, layout.NextRow);
|
|
||||||
layout.Size = new MuVec2(layout.Size.X, height); // assuming Size is MuVec2, updating only Y component
|
|
||||||
layout.ItemIndex = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static MuContainer? GetContainer(MuContext ctx, uint id, int opt)
|
|
||||||
{
|
|
||||||
//int idx = MuPool.Get(ctx, ctx.ContainerPool, ctx.Containers.Length, id); // TODO: Implement MuPool
|
|
||||||
int idx = MuPool.Get(ctx, ctx.ContainerPool, id); // TODO: Implement MuPool
|
|
||||||
if (idx >= 0)
|
if (idx >= 0)
|
||||||
{
|
{
|
||||||
if (ctx.Containers[idx].Open || (opt & (int)Options.Closed) == 0)
|
if (ctx.Containers[idx].Open || (opt & (int)Options.Closed) == 0)
|
||||||
{
|
{
|
||||||
//MuPool.Update(ctx, ctx.ContainerPool, idx); // TODO: Implement MuPool
|
MuPool.Update(ctx, ctx.ContainerPool, idx);
|
||||||
MuPool.Update(ctx, ctx.ContainerPool, idx); // TODO: Implement MuPool
|
|
||||||
}
|
}
|
||||||
return ctx.Containers[idx];
|
return ctx.Containers[idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new container
|
// If we're looking for a closed container and it doesn't exist, return null
|
||||||
//idx = MuPool.Init(ctx, ctx.ContainerPool, ctx.Containers.Length, id); // TODO: Implement MuPool
|
if ((opt & (int)Options.Closed) != 0)
|
||||||
//ref MuContainer cnt = ref ctx.Containers[idx];
|
{
|
||||||
//cnt = new MuContainer(); // Reset all fields
|
return null;
|
||||||
//cnt.Open = true;
|
}
|
||||||
//BringToFront(ctx, ref cnt); // TODO: Implement BringToFront
|
|
||||||
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);
|
||||||
|
cnt.Body = new MuRect(0, 0, 0, 0);
|
||||||
|
cnt.ContentSize = new MuVec2(0, 0);
|
||||||
|
cnt.Scroll = new MuVec2(0, 0);
|
||||||
|
cnt.ZIndex = 0;
|
||||||
|
cnt.Open = true;
|
||||||
|
|
||||||
|
BringToFront(ctx, cnt);
|
||||||
|
return cnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void BringToFront(MuContext ctx, MuContainer cnt)
|
||||||
|
{
|
||||||
|
cnt.ZIndex = ++ctx.LastZIndex;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class MuPool
|
public static class MuPool
|
||||||
@ -875,4 +895,408 @@ namespace MicroUI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class MuCommandList
|
||||||
|
{
|
||||||
|
public static void Push(MuContext ctx, MuCommand cmd)
|
||||||
|
{
|
||||||
|
ctx.CommandList.Push(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MuCommand? NextCommand(MuContext ctx, ref int index)
|
||||||
|
{
|
||||||
|
var commands = ctx.CommandList.Items;
|
||||||
|
int count = ctx.CommandList.Index;
|
||||||
|
|
||||||
|
while (index < count)
|
||||||
|
{
|
||||||
|
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
|
||||||
|
index = jump.DestinationIndex;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Return the current command and advance index
|
||||||
|
return commands[index++];
|
||||||
|
}
|
||||||
|
return null; // End of command list
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MuJumpCommand PushJump(MuContext ctx, int destinationIndex = -1)
|
||||||
|
{
|
||||||
|
var jump = new MuJumpCommand { DestinationIndex = destinationIndex };
|
||||||
|
ctx.CommandList.Push(jump);
|
||||||
|
return jump;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetClip(MuContext ctx, MuRect rect)
|
||||||
|
{
|
||||||
|
MuCommandList.Push(ctx, new MuClipCommand(rect));
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
MuCommandList.Push(ctx, new MuRectCommand(rect, color));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DrawBox(MuContext ctx, MuRect rect, MuColor color)
|
||||||
|
{
|
||||||
|
DrawRect(ctx, new MuRect(rect.X + 1, rect.Y, rect.W - 2, 1), color);
|
||||||
|
DrawRect(ctx, new MuRect(rect.X + 1, rect.Y + rect.H - 1, rect.W - 2, 1), color);
|
||||||
|
DrawRect(ctx, new MuRect(rect.X, rect.Y, 1, rect.H), color);
|
||||||
|
DrawRect(ctx, new MuRect(rect.X + rect.W - 1, rect.Y, 1, rect.H), color);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DrawText(MuContext ctx, object? font, string str, MuVec2 pos, MuColor color)
|
||||||
|
{
|
||||||
|
int len = str.Length;
|
||||||
|
int w = ctx.TextWidth != null ? ctx.TextWidth(font, str, len) : 0;
|
||||||
|
int h = ctx.TextHeight != null ? ctx.TextHeight(font) : 0;
|
||||||
|
var rect = new MuRect(pos.X, pos.Y, w, h);
|
||||||
|
|
||||||
|
var clipped = MicroUI.CheckClip(ctx, rect);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DrawIcon(MuContext ctx, int id, MuRect rect, MuColor color)
|
||||||
|
{
|
||||||
|
var clipped = MicroUI.CheckClip(ctx, rect);
|
||||||
|
if (clipped == ClipMode.All) return;
|
||||||
|
if (clipped == ClipMode.Part) SetClip(ctx, MicroUI.GetClipRect(ctx));
|
||||||
|
|
||||||
|
MuCommandList.Push(ctx, new MuIconCommand(rect, id, color));
|
||||||
|
|
||||||
|
if (clipped != 0) SetClip(ctx, MicroUI.UnclippedRect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Layout next type enum (matches C enum { RELATIVE = 1, ABSOLUTE = 2 })
|
||||||
|
enum LayoutNextType
|
||||||
|
{
|
||||||
|
Relative = 1,
|
||||||
|
Absolute = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class MuLayoutUtil
|
||||||
|
{
|
||||||
|
public static void LayoutBeginColumn(MuContext ctx)
|
||||||
|
{
|
||||||
|
var rect = LayoutNext(ctx);
|
||||||
|
MicroUI.PushLayout(ctx, rect, new MuVec2(0, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
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(
|
||||||
|
MathUtil.Max(a.Position.X, b.Position.X + b.Body.X - a.Body.X),
|
||||||
|
a.Position.Y
|
||||||
|
);
|
||||||
|
a.NextRow = MathUtil.Max(a.NextRow, b.NextRow + b.Body.Y - a.Body.Y);
|
||||||
|
a.Max = new MuVec2(
|
||||||
|
MathUtil.Max(a.Max.X, b.Max.X),
|
||||||
|
MathUtil.Max(a.Max.Y, b.Max.Y)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void LayoutRow(MuContext ctx, int items, int[]? widths, int height)
|
||||||
|
{
|
||||||
|
ref var layout = ref MicroUI.GetLayout(ctx);
|
||||||
|
|
||||||
|
if (widths != null)
|
||||||
|
{
|
||||||
|
MuAssert.Expect(items <= Constants.MaxWidths);
|
||||||
|
Array.Copy(widths, layout.Widths, items);
|
||||||
|
}
|
||||||
|
layout.Items = items;
|
||||||
|
layout.Position = new MuVec2(layout.Indent, layout.NextRow);
|
||||||
|
layout.Size = new MuVec2(layout.Size.X, height); // Only Y is updated
|
||||||
|
layout.ItemIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void LayoutWidth(MuContext ctx, int width)
|
||||||
|
{
|
||||||
|
ref var layout = ref MicroUI.GetLayout(ctx);
|
||||||
|
layout.Size = new MuVec2(width, layout.Size.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void LayoutHeight(MuContext ctx, int height)
|
||||||
|
{
|
||||||
|
ref var layout = ref MicroUI.GetLayout(ctx);
|
||||||
|
layout.Size = new MuVec2(layout.Size.X, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void LayoutSetNext(MuContext ctx, MuRect r, bool relative)
|
||||||
|
{
|
||||||
|
ref var layout = ref MicroUI.GetLayout(ctx);
|
||||||
|
layout.Next = r;
|
||||||
|
layout.NextType = relative ? (int)LayoutNextType.Relative : (int)LayoutNextType.Absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MuRect LayoutNext(MuContext ctx)
|
||||||
|
{
|
||||||
|
ref var layout = ref MicroUI.GetLayout(ctx);
|
||||||
|
var style = ctx.Style;
|
||||||
|
MuRect res;
|
||||||
|
|
||||||
|
if (layout.NextType != 0)
|
||||||
|
{
|
||||||
|
int type = layout.NextType;
|
||||||
|
layout.NextType = 0;
|
||||||
|
res = layout.Next;
|
||||||
|
if (type == (int)LayoutNextType.Absolute)
|
||||||
|
{
|
||||||
|
ctx.LastRect = res;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
if (res.H == 0) res.H = style.Size.Y + style.Padding * 2;
|
||||||
|
if (res.W < 0) res.W += layout.Body.W - res.X + 1;
|
||||||
|
if (res.H < 0) res.H += layout.Body.H - res.Y + 1;
|
||||||
|
|
||||||
|
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)
|
||||||
|
);
|
||||||
|
|
||||||
|
ctx.LastRect = res;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class MuControl
|
||||||
|
{
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
if (headJump != null)
|
||||||
|
{
|
||||||
|
headJump.DestinationIndex = ctx.CommandList.Index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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); // Implement or comment out
|
||||||
|
//MuControl.DrawControlText(ctx, title, tr, ColorType.TitleText, opt); // Implement or comment out
|
||||||
|
|
||||||
|
// Move window if dragging title bar
|
||||||
|
if (titleId == ctx.Focus && (ctx.MouseDown & (int)MouseButton.Left) != 0)
|
||||||
|
{
|
||||||
|
cnt.Rect = new MuRect(
|
||||||
|
cnt.Rect.X + ctx.MouseDelta.X,
|
||||||
|
cnt.Rect.Y + ctx.MouseDelta.Y,
|
||||||
|
cnt.Rect.W,
|
||||||
|
cnt.Rect.H
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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"));
|
||||||
|
var r = new MuRect(tr.X + tr.W - tr.H, tr.Y, tr.H, tr.H);
|
||||||
|
tr.W -= r.W;
|
||||||
|
//MuControl.DrawIcon(ctx, (int)IconType.Close, r, ctx.Style.Colors[(int)ColorType.TitleText]); // Implement or comment out
|
||||||
|
//MuControl.UpdateControl(ctx, closeId, r, opt); // Implement or comment out
|
||||||
|
if ((ctx.MousePressed & (int)MouseButton.Left) != 0 && closeId == ctx.Focus)
|
||||||
|
{
|
||||||
|
cnt.Open = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 7. Push Container Body Layout
|
||||||
|
MuControl.PushContainerBody(ctx, cnt, body, opt); // Implement or comment out
|
||||||
|
|
||||||
|
// 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); // Implement or comment out
|
||||||
|
if (resizeId == ctx.Focus && (ctx.MouseDown & (int)MouseButton.Left) != 0)
|
||||||
|
{
|
||||||
|
cnt.Rect = new MuRect(
|
||||||
|
cnt.Rect.X,
|
||||||
|
cnt.Rect.Y,
|
||||||
|
MathUtil.Max(96, cnt.Rect.W + ctx.MouseDelta.X),
|
||||||
|
MathUtil.Max(64, cnt.Rect.H + ctx.MouseDelta.Y)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 9. Auto-size
|
||||||
|
if ((opt & (int)Options.AutoSize) != 0)
|
||||||
|
{
|
||||||
|
var r = MicroUI.GetLayout(ctx).Body;
|
||||||
|
cnt.Rect = new MuRect(
|
||||||
|
cnt.Rect.X,
|
||||||
|
cnt.Rect.Y,
|
||||||
|
cnt.ContentSize.X + (cnt.Rect.W - r.W),
|
||||||
|
cnt.ContentSize.Y + (cnt.Rect.H - r.H)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void EndWindow(MuContext ctx)
|
||||||
|
{
|
||||||
|
MicroUI.PopClipRect(ctx);
|
||||||
|
MuControl.EndRootContainer(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -1,6 +1,7 @@
|
|||||||
using Raylib_cs;
|
using Raylib_cs;
|
||||||
|
using MicroUI;
|
||||||
|
|
||||||
namespace HelloWorld;
|
namespace MicroUI;
|
||||||
|
|
||||||
class Program
|
class Program
|
||||||
{
|
{
|
||||||
@ -10,14 +11,74 @@ class Program
|
|||||||
{
|
{
|
||||||
Raylib.InitWindow(800, 480, "Hello World");
|
Raylib.InitWindow(800, 480, "Hello World");
|
||||||
|
|
||||||
|
// Create microui context
|
||||||
|
var ctx = new MuContext();
|
||||||
|
|
||||||
|
// Set up required callbacks
|
||||||
|
ctx.TextWidth = (object font, string str, int len) =>
|
||||||
|
{
|
||||||
|
return str.Length * 8; // Simple approximation
|
||||||
|
};
|
||||||
|
|
||||||
|
ctx.TextHeight = (object font) =>
|
||||||
|
{
|
||||||
|
return 16; // Simple approximation
|
||||||
|
};
|
||||||
|
// Initialize microui
|
||||||
|
MicroUI.Init(ctx);
|
||||||
|
|
||||||
while (!Raylib.WindowShouldClose())
|
while (!Raylib.WindowShouldClose())
|
||||||
{
|
{
|
||||||
Raylib.BeginDrawing();
|
Raylib.BeginDrawing();
|
||||||
Raylib.ClearBackground(Color.White);
|
Raylib.ClearBackground(Color.White);
|
||||||
|
|
||||||
Raylib.DrawText("Hello, world!", 12, 12, 20, Color.Black);
|
// Begin frame
|
||||||
|
MicroUI.Begin(ctx);
|
||||||
|
if(MuControl.BeginWindowEx(ctx, "Test Window", new MuRect(100, 100, 100, 100), 0)){
|
||||||
|
|
||||||
|
MuControl.EndWindow(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(MuControl.BeginWindowEx(ctx, "Test Window 2", new MuRect(120, 120, 300, 200), 0)){
|
||||||
|
MuControl.EndWindow(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
// End frame
|
||||||
|
MicroUI.End(ctx);
|
||||||
|
|
||||||
|
// Print all commands in the command list
|
||||||
|
int cmdIndex = 0;
|
||||||
|
MuCommand? cmd = null;
|
||||||
|
while ((cmd = MuCommandList.NextCommand(ctx, ref cmdIndex)) != null)
|
||||||
|
{
|
||||||
|
Console.Write($"Command: {cmd.Type}");
|
||||||
|
switch (cmd)
|
||||||
|
{
|
||||||
|
case MuRectCommand rectCmd:
|
||||||
|
Console.Write($" | Rect: ({rectCmd.Rect.X},{rectCmd.Rect.Y},{rectCmd.Rect.W},{rectCmd.Rect.H}) Color: {rectCmd.Color.R},{rectCmd.Color.G},{rectCmd.Color.B},{rectCmd.Color.A}");
|
||||||
|
Raylib.DrawRectangle(rectCmd.Rect.X, rectCmd.Rect.Y, rectCmd.Rect.W, rectCmd.Rect.H, new Color(rectCmd.Color.R, rectCmd.Color.G, rectCmd.Color.B, rectCmd.Color.A));
|
||||||
|
break;
|
||||||
|
case MuClipCommand clipCmd:
|
||||||
|
Console.Write($" | Clip: ({clipCmd.Rect.X},{clipCmd.Rect.Y},{clipCmd.Rect.W},{clipCmd.Rect.H})");
|
||||||
|
break;
|
||||||
|
case MuJumpCommand jumpCmd:
|
||||||
|
Console.Write($" | Jump to: {jumpCmd.DestinationIndex}");
|
||||||
|
break;
|
||||||
|
case MuTextCommand textCmd:
|
||||||
|
Console.Write($" | Text: '{textCmd.Text}' at ({textCmd.Position.X},{textCmd.Position.Y}) Color: {textCmd.Color.R},{textCmd.Color.G},{textCmd.Color.B},{textCmd.Color.A}");
|
||||||
|
break;
|
||||||
|
case MuIconCommand iconCmd:
|
||||||
|
Console.Write($" | Icon: {iconCmd.IconId} Rect: ({iconCmd.Rect.X},{iconCmd.Rect.Y},{iconCmd.Rect.W},{iconCmd.Rect.H}) Color: {iconCmd.Color.R},{iconCmd.Color.G},{iconCmd.Color.B},{iconCmd.Color.A}");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Console.WriteLine("");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
Raylib.EndDrawing();
|
Raylib.EndDrawing();
|
||||||
|
|
||||||
|
//break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Raylib.CloseWindow();
|
Raylib.CloseWindow();
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user