Tests, original source for comparison, MuPool, logic fixes

This commit is contained in:
Bobby Lucero 2025-07-07 15:29:32 -04:00
parent a911d5310c
commit 7ae7e46a36
8 changed files with 1831 additions and 41 deletions

27
.gitignore vendored
View File

@ -1,3 +1,30 @@
MicroUI.cs/obj MicroUI.cs/obj
MicroUI.cs/bin MicroUI.cs/bin
.idea .idea
# C#/.NET build artifacts
bin/
obj/
*.user
*.suo
*.userosscache
*.sln.docstates
*.vs/
*.dll
*.exe
*.pdb
*.cache
*.log
TestResults/
MicroUI.Tests/bin/
MicroUI.Tests/obj/
# C build artifacts
C/*.o
C/*.out
C/*.a
C/*.so
C/*.dSYM/
C/microui_test
# OS/Editor files
.DS_Store
Thumbs.db
.vscode/

1208
C/MicroUI.c Normal file

File diff suppressed because it is too large Load Diff

296
C/MicroUI.h Normal file
View File

@ -0,0 +1,296 @@
/*
** Copyright (c) 2024 rxi
**
** This library is free software; you can redistribute it and/or modify it
** under the terms of the MIT license. See `microui.c` for details.
*/
#ifndef MICROUI_H
#define MICROUI_H
#define MU_VERSION "2.02"
#define MU_COMMANDLIST_SIZE (256 * 1024)
#define MU_ROOTLIST_SIZE 32
#define MU_CONTAINERSTACK_SIZE 32
#define MU_CLIPSTACK_SIZE 32
#define MU_IDSTACK_SIZE 32
#define MU_LAYOUTSTACK_SIZE 16
#define MU_CONTAINERPOOL_SIZE 48
#define MU_TREENODEPOOL_SIZE 48
#define MU_MAX_WIDTHS 16
#define MU_REAL float
#define MU_REAL_FMT "%.3g"
#define MU_SLIDER_FMT "%.2f"
#define MU_MAX_FMT 127
#define mu_stack(T, n) struct { int idx; T items[n]; }
#define mu_min(a, b) ((a) < (b) ? (a) : (b))
#define mu_max(a, b) ((a) > (b) ? (a) : (b))
#define mu_clamp(x, a, b) mu_min(b, mu_max(a, x))
enum {
MU_CLIP_PART = 1,
MU_CLIP_ALL
};
enum {
MU_COMMAND_JUMP = 1,
MU_COMMAND_CLIP,
MU_COMMAND_RECT,
MU_COMMAND_TEXT,
MU_COMMAND_ICON,
MU_COMMAND_MAX
};
enum {
MU_COLOR_TEXT,
MU_COLOR_BORDER,
MU_COLOR_WINDOWBG,
MU_COLOR_TITLEBG,
MU_COLOR_TITLETEXT,
MU_COLOR_PANELBG,
MU_COLOR_BUTTON,
MU_COLOR_BUTTONHOVER,
MU_COLOR_BUTTONFOCUS,
MU_COLOR_BASE,
MU_COLOR_BASEHOVER,
MU_COLOR_BASEFOCUS,
MU_COLOR_SCROLLBASE,
MU_COLOR_SCROLLTHUMB,
MU_COLOR_MAX
};
enum {
MU_ICON_CLOSE = 1,
MU_ICON_CHECK,
MU_ICON_COLLAPSED,
MU_ICON_EXPANDED,
MU_ICON_MAX
};
enum {
MU_RES_ACTIVE = (1 << 0),
MU_RES_SUBMIT = (1 << 1),
MU_RES_CHANGE = (1 << 2)
};
enum {
MU_OPT_ALIGNCENTER = (1 << 0),
MU_OPT_ALIGNRIGHT = (1 << 1),
MU_OPT_NOINTERACT = (1 << 2),
MU_OPT_NOFRAME = (1 << 3),
MU_OPT_NORESIZE = (1 << 4),
MU_OPT_NOSCROLL = (1 << 5),
MU_OPT_NOCLOSE = (1 << 6),
MU_OPT_NOTITLE = (1 << 7),
MU_OPT_HOLDFOCUS = (1 << 8),
MU_OPT_AUTOSIZE = (1 << 9),
MU_OPT_POPUP = (1 << 10),
MU_OPT_CLOSED = (1 << 11),
MU_OPT_EXPANDED = (1 << 12)
};
enum {
MU_MOUSE_LEFT = (1 << 0),
MU_MOUSE_RIGHT = (1 << 1),
MU_MOUSE_MIDDLE = (1 << 2)
};
enum {
MU_KEY_SHIFT = (1 << 0),
MU_KEY_CTRL = (1 << 1),
MU_KEY_ALT = (1 << 2),
MU_KEY_BACKSPACE = (1 << 3),
MU_KEY_RETURN = (1 << 4)
};
typedef struct mu_Context mu_Context;
typedef unsigned mu_Id;
typedef MU_REAL mu_Real;
typedef void* mu_Font;
typedef struct { int x, y; } mu_Vec2;
typedef struct { int x, y, w, h; } mu_Rect;
typedef struct { unsigned char r, g, b, a; } mu_Color;
typedef struct { mu_Id id; int last_update; } mu_PoolItem;
typedef struct { int type, size; } mu_BaseCommand;
typedef struct { mu_BaseCommand base; void *dst; } mu_JumpCommand;
typedef struct { mu_BaseCommand base; mu_Rect rect; } mu_ClipCommand;
typedef struct { mu_BaseCommand base; mu_Rect rect; mu_Color color; } mu_RectCommand;
typedef struct { mu_BaseCommand base; mu_Font font; mu_Vec2 pos; mu_Color color; char str[1]; } mu_TextCommand;
typedef struct { mu_BaseCommand base; mu_Rect rect; int id; mu_Color color; } mu_IconCommand;
typedef union {
int type;
mu_BaseCommand base;
mu_JumpCommand jump;
mu_ClipCommand clip;
mu_RectCommand rect;
mu_TextCommand text;
mu_IconCommand icon;
} mu_Command;
typedef struct {
mu_Rect body;
mu_Rect next;
mu_Vec2 position;
mu_Vec2 size;
mu_Vec2 max;
int widths[MU_MAX_WIDTHS];
int items;
int item_index;
int next_row;
int next_type;
int indent;
} mu_Layout;
typedef struct {
mu_Command *head, *tail;
mu_Rect rect;
mu_Rect body;
mu_Vec2 content_size;
mu_Vec2 scroll;
int zindex;
int open;
} mu_Container;
typedef struct {
mu_Font font;
mu_Vec2 size;
int padding;
int spacing;
int indent;
int title_height;
int scrollbar_size;
int thumb_size;
mu_Color colors[MU_COLOR_MAX];
} mu_Style;
struct mu_Context {
/* callbacks */
int (*text_width)(mu_Font font, const char *str, int len);
int (*text_height)(mu_Font font);
void (*draw_frame)(mu_Context *ctx, mu_Rect rect, int colorid);
/* core state */
mu_Style _style;
mu_Style *style;
mu_Id hover;
mu_Id focus;
mu_Id last_id;
mu_Rect last_rect;
int last_zindex;
int updated_focus;
int frame;
mu_Container *hover_root;
mu_Container *next_hover_root;
mu_Container *scroll_target;
char number_edit_buf[MU_MAX_FMT];
mu_Id number_edit;
/* stacks */
mu_stack(char, MU_COMMANDLIST_SIZE) command_list;
mu_stack(mu_Container*, MU_ROOTLIST_SIZE) root_list;
mu_stack(mu_Container*, MU_CONTAINERSTACK_SIZE) container_stack;
mu_stack(mu_Rect, MU_CLIPSTACK_SIZE) clip_stack;
mu_stack(mu_Id, MU_IDSTACK_SIZE) id_stack;
mu_stack(mu_Layout, MU_LAYOUTSTACK_SIZE) layout_stack;
/* retained state pools */
mu_PoolItem container_pool[MU_CONTAINERPOOL_SIZE];
mu_Container containers[MU_CONTAINERPOOL_SIZE];
mu_PoolItem treenode_pool[MU_TREENODEPOOL_SIZE];
/* input state */
mu_Vec2 mouse_pos;
mu_Vec2 last_mouse_pos;
mu_Vec2 mouse_delta;
mu_Vec2 scroll_delta;
int mouse_down;
int mouse_pressed;
int key_down;
int key_pressed;
char input_text[32];
};
mu_Vec2 mu_vec2(int x, int y);
mu_Rect mu_rect(int x, int y, int w, int h);
mu_Color mu_color(int r, int g, int b, int a);
void mu_init(mu_Context *ctx);
void mu_begin(mu_Context *ctx);
void mu_end(mu_Context *ctx);
void mu_set_focus(mu_Context *ctx, mu_Id id);
mu_Id mu_get_id(mu_Context *ctx, const void *data, int size);
void mu_push_id(mu_Context *ctx, const void *data, int size);
void mu_pop_id(mu_Context *ctx);
void mu_push_clip_rect(mu_Context *ctx, mu_Rect rect);
void mu_pop_clip_rect(mu_Context *ctx);
mu_Rect mu_get_clip_rect(mu_Context *ctx);
int mu_check_clip(mu_Context *ctx, mu_Rect r);
mu_Container* mu_get_current_container(mu_Context *ctx);
mu_Container* mu_get_container(mu_Context *ctx, const char *name);
void mu_bring_to_front(mu_Context *ctx, mu_Container *cnt);
int mu_pool_init(mu_Context *ctx, mu_PoolItem *items, int len, mu_Id id);
int mu_pool_get(mu_Context *ctx, mu_PoolItem *items, int len, mu_Id id);
void mu_pool_update(mu_Context *ctx, mu_PoolItem *items, int idx);
void mu_input_mousemove(mu_Context *ctx, int x, int y);
void mu_input_mousedown(mu_Context *ctx, int x, int y, int btn);
void mu_input_mouseup(mu_Context *ctx, int x, int y, int btn);
void mu_input_scroll(mu_Context *ctx, int x, int y);
void mu_input_keydown(mu_Context *ctx, int key);
void mu_input_keyup(mu_Context *ctx, int key);
void mu_input_text(mu_Context *ctx, const char *text);
mu_Command* mu_push_command(mu_Context *ctx, int type, int size);
int mu_next_command(mu_Context *ctx, mu_Command **cmd);
void mu_set_clip(mu_Context *ctx, mu_Rect rect);
void mu_draw_rect(mu_Context *ctx, mu_Rect rect, mu_Color color);
void mu_draw_box(mu_Context *ctx, mu_Rect rect, mu_Color color);
void mu_draw_text(mu_Context *ctx, mu_Font font, const char *str, int len, mu_Vec2 pos, mu_Color color);
void mu_draw_icon(mu_Context *ctx, int id, mu_Rect rect, mu_Color color);
void mu_layout_row(mu_Context *ctx, int items, const int *widths, int height);
void mu_layout_width(mu_Context *ctx, int width);
void mu_layout_height(mu_Context *ctx, int height);
void mu_layout_begin_column(mu_Context *ctx);
void mu_layout_end_column(mu_Context *ctx);
void mu_layout_set_next(mu_Context *ctx, mu_Rect r, int relative);
mu_Rect mu_layout_next(mu_Context *ctx);
void mu_draw_control_frame(mu_Context *ctx, mu_Id id, mu_Rect rect, int colorid, int opt);
void mu_draw_control_text(mu_Context *ctx, const char *str, mu_Rect rect, int colorid, int opt);
int mu_mouse_over(mu_Context *ctx, mu_Rect rect);
void mu_update_control(mu_Context *ctx, mu_Id id, mu_Rect rect, int opt);
#define mu_button(ctx, label) mu_button_ex(ctx, label, 0, MU_OPT_ALIGNCENTER)
#define mu_textbox(ctx, buf, bufsz) mu_textbox_ex(ctx, buf, bufsz, 0)
#define mu_slider(ctx, value, lo, hi) mu_slider_ex(ctx, value, lo, hi, 0, MU_SLIDER_FMT, MU_OPT_ALIGNCENTER)
#define mu_number(ctx, value, step) mu_number_ex(ctx, value, step, MU_SLIDER_FMT, MU_OPT_ALIGNCENTER)
#define mu_header(ctx, label) mu_header_ex(ctx, label, 0)
#define mu_begin_treenode(ctx, label) mu_begin_treenode_ex(ctx, label, 0)
#define mu_begin_window(ctx, title, rect) mu_begin_window_ex(ctx, title, rect, 0)
#define mu_begin_panel(ctx, name) mu_begin_panel_ex(ctx, name, 0)
void mu_text(mu_Context *ctx, const char *text);
void mu_label(mu_Context *ctx, const char *text);
int mu_button_ex(mu_Context *ctx, const char *label, int icon, int opt);
int mu_checkbox(mu_Context *ctx, const char *label, int *state);
int mu_textbox_raw(mu_Context *ctx, char *buf, int bufsz, mu_Id id, mu_Rect r, int opt);
int mu_textbox_ex(mu_Context *ctx, char *buf, int bufsz, int opt);
int mu_slider_ex(mu_Context *ctx, mu_Real *value, mu_Real low, mu_Real high, mu_Real step, const char *fmt, int opt);
int mu_number_ex(mu_Context *ctx, mu_Real *value, mu_Real step, const char *fmt, int opt);
int mu_header_ex(mu_Context *ctx, const char *label, int opt);
int mu_begin_treenode_ex(mu_Context *ctx, const char *label, int opt);
void mu_end_treenode(mu_Context *ctx);
int mu_begin_window_ex(mu_Context *ctx, const char *title, mu_Rect rect, int opt);
void mu_end_window(mu_Context *ctx);
void mu_open_popup(mu_Context *ctx, const char *name);
int mu_begin_popup(mu_Context *ctx, const char *name);
void mu_end_popup(mu_Context *ctx);
void mu_begin_panel_ex(mu_Context *ctx, const char *name, int opt);
void mu_end_panel(mu_Context *ctx);
#endif

10
C/main.c Normal file
View File

@ -0,0 +1,10 @@
#include "MicroUI.h"
#include <stdio.h>
int main(void) {
mu_Vec2 v = mu_vec2(1, 2);
mu_Rect r = mu_rect(3, 4, 5, 6);
printf("mu_Vec2: (%d, %d)\n", v.x, v.y);
printf("mu_Rect: (%d, %d, %d, %d)\n", r.x, r.y, r.w, r.h);
return 0;
}

View File

@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="xunit" Version="2.5.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3" />
</ItemGroup>
<ItemGroup>
<Using Include="Xunit" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MicroUI.cs\MicroUI.cs.csproj" />
</ItemGroup>
</Project>

202
MicroUI.Tests/UnitTest1.cs Normal file
View File

@ -0,0 +1,202 @@
using Xunit;
using MicroUI;
using System;
public class BasicTests : IDisposable
{
public BasicTests()
{
MuAssert.TestMode = true;
}
public void Dispose()
{
MuAssert.TestMode = false;
}
[Fact]
public void MathUtil_Clamp_Int_WorksLikeC()
{
Assert.Equal(5, MathUtil.Clamp(5, 0, 10));
Assert.Equal(0, MathUtil.Clamp(-5, 0, 10));
Assert.Equal(10, MathUtil.Clamp(15, 0, 10));
}
[Fact]
public void MathUtil_Clamp_Float_WorksLikeC()
{
Assert.Equal(5.0f, MathUtil.Clamp(5.0f, 0.0f, 10.0f));
Assert.Equal(0.0f, MathUtil.Clamp(-5.0f, 0.0f, 10.0f));
Assert.Equal(10.0f, MathUtil.Clamp(15.0f, 0.0f, 10.0f));
}
[Fact]
public void FixedStack_PushPop_Works()
{
var stack = new FixedStack<int>(4);
stack.Push(1);
stack.Push(2);
Assert.Equal(2, stack.Pop());
Assert.Equal(1, stack.Pop());
}
[Fact]
public void FixedStack_Peek_Works()
{
var stack = new FixedStack<int>(4);
stack.Push(42);
Assert.Equal(42, stack.Peek());
}
[Fact]
public void FixedStack_Clear_ResetsIndex()
{
var stack = new FixedStack<int>(4);
stack.Push(1);
stack.Push(2);
stack.Clear();
Assert.Equal(0, stack.Index);
}
[Fact]
public void MuVec2_ConstructsCorrectly()
{
var v = new MuVec2(3, 7);
Assert.Equal(3, v.X);
Assert.Equal(7, v.Y);
}
[Fact]
public void MuRect_ConstructsCorrectly()
{
var r = new MuRect(1, 2, 3, 4);
Assert.Equal(1, r.X);
Assert.Equal(2, r.Y);
Assert.Equal(3, r.W);
Assert.Equal(4, r.H);
}
[Fact]
public void MuColor_ConstructsCorrectly()
{
var c = new MuColor(10, 20, 30, 40);
Assert.Equal((byte)10, c.R);
Assert.Equal((byte)20, c.G);
Assert.Equal((byte)30, c.B);
Assert.Equal((byte)40, c.A);
}
[Fact]
public void MuPool_GetAndInit_Works()
{
var ctx = new MuContext();
ctx.Frame = 1;
var pool = new MuPoolItem[4];
uint id1 = 123, id2 = 456;
// Initially not found
Assert.Equal(-1, MuPool.Get(ctx, pool, id1));
// Init first
int idx1 = MuPool.Init(ctx, pool, id1);
Assert.Equal(id1, pool[idx1].Id);
// Should now be found
Assert.Equal(idx1, MuPool.Get(ctx, pool, id1));
// Init second
int idx2 = MuPool.Init(ctx, pool, id2);
Assert.Equal(id2, pool[idx2].Id);
Assert.Equal(idx2, MuPool.Get(ctx, pool, id2));
}
[Fact]
public void MuPool_Update_SetsLastUpdate()
{
var ctx = new MuContext();
ctx.Frame = 42;
var pool = new MuPoolItem[2];
int idx = MuPool.Init(ctx, pool, 1);
MuPool.Update(ctx, pool, idx);
Assert.Equal(42, pool[idx].LastUpdate);
}
[Fact]
public void MuAssert_Expect_ThrowsOnFalse()
{
var ex = Assert.Throws<Exception>(() => MuAssert.Expect(false));
Assert.Contains("assertion failed", ex.Message);
}
[Fact]
public void MuPool_RecyclesLeastRecentlyUsedSlot()
{
var ctx = new MuContext();
ctx.Frame = 1;
var pool = new MuPoolItem[2];
int idx1 = MuPool.Init(ctx, pool, 100);
ctx.Frame++;
int idx2 = MuPool.Init(ctx, pool, 200);
Assert.NotEqual(idx1, idx2);
// Both slots are now used, next init should recycle the LRU (idx1)
ctx.Frame++;
int idx3 = MuPool.Init(ctx, pool, 300);
Assert.Equal(idx1, idx3); // idx1 was least recently used
Assert.Equal(300u, pool[idx3].Id);
}
[Fact]
public void MuPool_GetReturnsMinusOneForMissingId()
{
var ctx = new MuContext();
ctx.Frame = 1;
var pool = new MuPoolItem[2];
Assert.Equal(-1, MuPool.Get(ctx, pool, 999));
}
[Fact]
public void MuPool_InitThrowsIfNoSlotAvailable()
{
var ctx = new MuContext();
ctx.Frame = 0;
var pool = new MuPoolItem[1];
pool[0].LastUpdate = 0;
// This will throw because no slot is older than frame 0
Assert.Throws<Exception>(() => MuPool.Init(ctx, pool, 1));
}
[Fact]
public void MuRect_Equality_Works()
{
var a = new MuRect(1, 2, 3, 4);
var b = new MuRect(1, 2, 3, 4);
var c = new MuRect(0, 0, 0, 0);
Assert.Equal(a.X, b.X);
Assert.Equal(a.Y, b.Y);
Assert.Equal(a.W, b.W);
Assert.Equal(a.H, b.H);
Assert.NotEqual(a.X, c.X);
}
[Fact]
public void MuVec2_Arithmetic_Works()
{
var a = new MuVec2(2, 3);
var b = new MuVec2(4, 5);
var sum = new MuVec2(a.X + b.X, a.Y + b.Y);
Assert.Equal(6, sum.X);
Assert.Equal(8, sum.Y);
}
[Fact]
public void FixedStack_Overflow_Throws()
{
var stack = new FixedStack<int>(2);
stack.Push(1);
stack.Push(2);
// Next push should trigger assertion (but not throw in release)
Assert.Throws<Exception>(() => stack.Push(3));
}
[Fact]
public void FixedStack_Underflow_Throws()
{
var stack = new FixedStack<int>(2);
Assert.Throws<Exception>(() => stack.Pop());
}
}

View File

@ -417,13 +417,51 @@ namespace MicroUI
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 char[] inputText = new char[32];
}
public static class MuPool
{
public static int Get(MuContext ctx, MuPoolItem[] items, uint id)
{
for (int i = 0; i < items.Length; i++)
{
if (items[i].Id == id)
{
return i;
}
}
return -1;
}
public static int Init(MuContext ctx, MuPoolItem[] items, uint id)
{
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)
{
f = items[i].LastUpdate;
n = i;
}
}
MuAssert.Expect(n > -1);
items[n].Id = id;
Update(ctx, items, n);
return n;
}
public static void Update(MuContext ctx, MuPoolItem[] items, int idx)
{
items[idx].LastUpdate = ctx.Frame;
}
} }
public static class MuAssert public static class MuAssert
{ {
public static bool TestMode { get; set; } = false;
public static void Expect(bool condition, public static void Expect(bool condition,
[CallerFilePath] string file = "", [CallerFilePath] string file = "",
[CallerLineNumber] int line = 0, [CallerLineNumber] int line = 0,
@ -431,7 +469,10 @@ namespace MicroUI
{ {
if (!condition) if (!condition)
{ {
Console.Error.WriteLine($"Fatal error at {file}:{line} in {member}: assertion failed."); var msg = $"Fatal error at {file}:{line} in {member}: assertion failed.";
Console.Error.WriteLine(msg);
if (TestMode)
throw new Exception(msg);
Environment.FailFast("Expectation failed."); Environment.FailFast("Expectation failed.");
} }
} }
@ -502,7 +543,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]); //DrawRect(ctx, rect, ctx.Style.Colors[(int)colorId]); // TODO: Implement DrawRect
// Early return for certain color IDs (skip border) // Early return for certain color IDs (skip border)
if (colorId == ColorType.ScrollBase || if (colorId == ColorType.ScrollBase ||
@ -515,7 +556,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]); //DrawBox(ctx, ExpandRect(rect, 1), ctx.Style.Colors[(int)ColorType.Border]); // TODO: Implement DrawBox
} }
} }
@ -577,7 +618,7 @@ namespace MicroUI
ctx.NextHoverRoot.ZIndex < ctx.LastZIndex && ctx.NextHoverRoot.ZIndex < ctx.LastZIndex &&
ctx.NextHoverRoot.ZIndex >= 0) ctx.NextHoverRoot.ZIndex >= 0)
{ {
BringToFront(ctx.NextHoverRoot); //BringToFront(ctx.NextHoverRoot); // TODO: Implement BringToFront
} }
ctx.KeyPressed = 0; ctx.KeyPressed = 0;
@ -603,14 +644,12 @@ namespace MicroUI
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 // 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)
{ {
// Last container tail jump destination points to end of command list (beyond last command) // Set last container's tail jump to the end of the command list
((MuJumpCommand)ctx.CommandList.Items[cnt.TailIndex]).DestinationIndex = cnt.HeadIndex + 1; ((MuJumpCommand)ctx.CommandList.Items[cnt.TailIndex]).DestinationIndex = ctx.CommandList.Index;
} }
} }
} }
@ -763,46 +802,27 @@ namespace MicroUI
static MuContainer? GetContainer(MuContext ctx, uint id, int opt) static MuContainer? GetContainer(MuContext ctx, uint id, int opt)
{ {
// Try to get an existing container from the pool //int idx = MuPool.Get(ctx, ctx.ContainerPool, ctx.Containers.Length, id); // TODO: Implement MuPool
int idx = MuPool.Get(ctx, ctx.ContainerPool, ctx.Containers.Length, id); int idx = MuPool.Get(ctx, ctx.ContainerPool, id); // TODO: Implement MuPool
if (idx >= 0) if (idx >= 0)
{ {
if (ctx.Containers[idx].Open || (opt & (int)Option.Closed) == 0) if (ctx.Containers[idx].Open || (opt & (int)Options.Closed) == 0)
{ {
MuPool.Update(ctx, ctx.ContainerPool, idx); //MuPool.Update(ctx, ctx.ContainerPool, idx); // TODO: Implement MuPool
MuPool.Update(ctx, ctx.ContainerPool, idx); // TODO: Implement MuPool
} }
return ctx.Containers[idx]; return ctx.Containers[idx];
} }
// If container is closed, return null // Create a new container
if ((opt & (int)Option.Closed) != 0) //idx = MuPool.Init(ctx, ctx.ContainerPool, ctx.Containers.Length, id); // TODO: Implement MuPool
{ //ref MuContainer cnt = ref ctx.Containers[idx];
//cnt = new MuContainer(); // Reset all fields
//cnt.Open = true;
//BringToFront(ctx, ref cnt); // TODO: Implement BringToFront
return null; return null;
} }
// Create a new container
idx = MuPool.Init(ctx, ctx.ContainerPool, ctx.Containers.Length, id);
ref MuContainer cnt = ref ctx.Containers[idx];
cnt = new MuContainer(); // Reset all fields
cnt.Open = true;
BringToFront(ctx, ref cnt);
return cnt;
}
public static int Get(MuContext ctx, MuPoolItem[] items, int length, uint id)
{
for (int i = 0; i < length; i++)
{
if (items[i].Id == id)
{
return i;
}
}
return -1;
}
} }
} }

View File

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>