Started modeling an interface. Early MicroUI backend.

This commit is contained in:
2026-02-10 11:38:37 +01:00
parent 07c01b4b38
commit ac81bf5aaf
2 changed files with 397 additions and 1 deletions

View File

@@ -1,3 +1,249 @@
package imgui
// Hello, world!
import "core:container/queue"
import "core:log"
import "microui"
MAX_DRAW_COMMANDS :: #config(IMGUI_MAX_DRAW_COMMANDS, 512 * 1024)
// TODO: SS - Consider not having 'microui' as a seperate package and instead have it (and other backends) in the 'imgui' package directly.
IMGUI_BACKEND_MICROUI :: #config(IMGUI_BACKEND_MICROUI, false)
when IMGUI_BACKEND_MICROUI {
Context_Backend :: microui.Context
}
Context :: struct {
backend: ^Context_Backend,
draw_commands: queue.Queue(Draw_Command),
input: Input,
}
Input :: struct {
mouse_state: Mouse_State,
}
Mouse_Button_State :: enum {
Up,
Pressed,
Down,
Released,
}
Mouse_State :: struct {
pos_x, pos_y: u16,
left, middle, right: Mouse_Button_State,
}
Draw_Command :: struct {
color: [4]u8,
type: Draw_Command_Type,
}
Draw_Command_Type :: union {
Draw_Command_Rect,
}
Draw_Command_Rect :: struct {
x, y, width, height: u16,
}
Rect :: struct {
x, y, width, height: u16,
}
init :: proc(ctx: ^Context) -> bool {
assert(ctx != nil)
assert(ctx.backend == nil)
backend, err := new(Context_Backend)
if err != .None {
log.errorf("Failed to allocate space for the backend. Error: %v", err)
return false
}
ctx.backend = backend
ok := false
when IMGUI_BACKEND_MICROUI {
ok = microui.init(ctx.backend)
}
if !ok {
free(backend)
return false
}
queue_err := queue.init(&ctx.draw_commands, MAX_DRAW_COMMANDS)
if queue_err != .None {
free(backend)
log.errorf("Failed to allocate space for the queue of imgui draw-commands. Error: %v", queue_err)
return false
}
return true
}
set_input :: proc(ctx: ^Context, input: Input) {
ctx.input = input
}
begin :: proc(ctx: ^Context) {
assert(ctx != nil)
assert(ctx.backend != nil)
when IMGUI_BACKEND_MICROUI {
input: microui.Input
input.mouse_x = ctx.input.mouse_state.pos_x
input.mouse_y = ctx.input.mouse_state.pos_y
if ctx.input.mouse_state.left == .Pressed {
input.mouse_buttons_pressed += { .LEFT }
}
else if ctx.input.mouse_state.left == .Released {
input.mouse_buttons_released += { .LEFT }
}
if ctx.input.mouse_state.middle == .Pressed {
input.mouse_buttons_pressed += { .MIDDLE }
}
else if ctx.input.mouse_state.middle == .Released {
input.mouse_buttons_released += { .MIDDLE }
}
if ctx.input.mouse_state.right == .Pressed {
input.mouse_buttons_pressed += { .RIGHT }
}
else if ctx.input.mouse_state.right == .Released {
input.mouse_buttons_released += { .RIGHT }
}
microui.begin(ctx.backend, input)
}
}
end :: proc(ctx: ^Context) {
assert(ctx != nil)
assert(ctx.backend != nil)
when IMGUI_BACKEND_MICROUI {
microui.end(ctx.backend)
}
}
begin_window :: proc(ctx: ^Context, title: string, rect: Rect) -> bool {
assert(ctx != nil)
when IMGUI_BACKEND_MICROUI {
return microui.begin_window(ctx.backend, title, microui.Rect {
x = i32(rect.x),
y = i32(rect.y),
w = i32(rect.width),
h = i32(rect.height),
})
}
return false
}
end_window :: proc(ctx: ^Context) {
assert(ctx != nil)
when IMGUI_BACKEND_MICROUI {
microui.end_window(ctx.backend)
}
}
button :: proc(ctx: ^Context, title: string) -> bool {
when IMGUI_BACKEND_MICROUI {
return microui.button(ctx.backend, title)
}
return false
}
collect :: proc(ctx: ^Context) { // TODO: SS - Come up with a better name. Adds commands from backend to queue in ctx.
assert(ctx != nil)
// TODO: SS - Reduce code-repetition if possible. MicroUI asks to be "popped"/iterated like this, apparently.
when IMGUI_BACKEND_MICROUI {
last_cmd: ^microui.Command = nil
for {
dc: Draw_Command
dc.type = nil
cmd := microui.pop_draw_command(ctx.backend, last_cmd)
if cmd == nil {
break
}
last_cmd = cmd
#partial switch &v in &cmd.variant {
// case ^microui.Command_Jump: {} // Internal.
// case ^microui.Command_Clip: {
// }
// case ^microui.Command_Icon: {
// }
case ^microui.Command_Rect: {
assert(v.rect.x >= 0)
assert(v.rect.y >= 0)
assert(v.rect.w >= 0)
assert(v.rect.h >= 0)
dc.color = {
v.color.r,
v.color.g,
v.color.b,
v.color.a,
}
dc.type = Draw_Command_Rect {
x = u16(v.rect.x),
y = u16(v.rect.y),
width = u16(v.rect.w),
height = u16(v.rect.h),
}
}
// case ^microui.Command_Text: {
// }
}
if dc.type != nil {
queue.push_back(&ctx.draw_commands, dc)
}
}
}
}
pop_draw_command :: proc(ctx: ^Context, out_draw_command: ^Draw_Command) -> bool {
assert(ctx != nil)
assert(out_draw_command != nil)
out_draw_command^ = {}
elem, ok := queue.pop_front_safe(&ctx.draw_commands)
if !ok {
return false
}
out_draw_command^ = elem
return true
}
shutdown :: proc(ctx: ^Context) {
assert(ctx != nil)
assert(ctx.backend != nil)
when IMGUI_BACKEND_MICROUI {
microui.shutdown(ctx.backend)
}
free(ctx.backend)
ctx.backend = nil
queue.destroy(&ctx.draw_commands)
}