190 lines
4.2 KiB
Odin
190 lines
4.2 KiB
Odin
package sectr
|
|
|
|
UI_Floating :: struct {
|
|
label : string,
|
|
using links : DLL_NodePN(UI_Floating),
|
|
captures : rawptr,
|
|
builder : UI_FloatingBuilder,
|
|
queued : b32,
|
|
}
|
|
UI_FloatingBuilder :: #type proc( captures : rawptr ) -> (became_active : b32)
|
|
|
|
// Overlapping/Stacking window/frame manager
|
|
// AKA: Stacking or Floating Window Manager
|
|
UI_FloatingManager :: struct {
|
|
using links : DLL_NodeFL(UI_Floating),
|
|
build_queue : Array(UI_Floating),
|
|
tracked : HMapZPL(UI_Floating),
|
|
}
|
|
|
|
ui_floating_startup :: proc( self : ^UI_FloatingManager, allocator : Allocator, build_queue_cap, tracked_cap : u64, dbg_name : string = "" ) -> AllocatorError
|
|
{
|
|
error : AllocatorError
|
|
|
|
queue_dbg_name := str_intern(str_fmt_tmp("%s: build_queue", dbg_name))
|
|
self.build_queue, error = array_init_reserve( UI_Floating, allocator, build_queue_cap, dbg_name = queue_dbg_name.str )
|
|
if error != AllocatorError.None
|
|
{
|
|
ensure(false, "Failed to allocate the build_queue")
|
|
return error
|
|
}
|
|
|
|
tracked_dbg_name := str_intern(str_fmt_tmp("%s: tracked", dbg_name))
|
|
self.tracked, error = zpl_hmap_init_reserve( UI_Floating, allocator, tracked_cap, dbg_name = tracked_dbg_name.str )
|
|
if error != AllocatorError.None
|
|
{
|
|
ensure(false, "Failed to allocate tracking table")
|
|
return error
|
|
}
|
|
return error
|
|
}
|
|
|
|
ui_floating_just_builder :: #force_inline proc( label : string, builder : UI_FloatingBuilder ) -> ^UI_Floating
|
|
{
|
|
No_Captures : rawptr = nil
|
|
return ui_floating_with_capture(label, No_Captures, builder)
|
|
}
|
|
|
|
ui_floating_with_capture :: proc( label : string, captures : rawptr = nil, builder : UI_FloatingBuilder ) -> ^UI_Floating
|
|
{
|
|
entry := UI_Floating {
|
|
label = label,
|
|
captures = captures,
|
|
builder = builder,
|
|
}
|
|
|
|
floating := get_state().ui_floating_context
|
|
array_append( & floating.build_queue, entry )
|
|
return nil
|
|
}
|
|
|
|
@(deferred_none = ui_floating_manager_end)
|
|
ui_floating_manager :: proc ( manager : ^UI_FloatingManager )
|
|
{
|
|
ui_floating_manager_begin(manager)
|
|
}
|
|
|
|
ui_floating_manager_begin :: proc ( manager : ^UI_FloatingManager )
|
|
{
|
|
state := get_state()
|
|
state.ui_floating_context = manager
|
|
}
|
|
|
|
ui_floating_manager_end :: proc()
|
|
{
|
|
state := get_state()
|
|
floating := & state.ui_floating_context
|
|
ui_floating_build()
|
|
floating = nil
|
|
}
|
|
|
|
ui_floating_build :: proc()
|
|
{
|
|
ui := ui_context()
|
|
screen_ui := cast(^UI_ScreenState) ui
|
|
using floating := get_state().ui_floating_context
|
|
|
|
for to_enqueue in array_to_slice_num( build_queue)
|
|
{
|
|
key := ui_key_from_string(to_enqueue.label)
|
|
lookup := zpl_hmap_get( & tracked, transmute(u64) key )
|
|
|
|
// Check if entry is already present
|
|
if lookup != nil && lookup.prev != nil && lookup.next != nil {
|
|
lookup.captures = to_enqueue.captures
|
|
lookup.builder = to_enqueue.builder
|
|
lookup.queued = true
|
|
continue
|
|
}
|
|
|
|
if lookup == nil {
|
|
error : AllocatorError
|
|
lookup, error = zpl_hmap_set( & tracked, transmute(u64) key, to_enqueue )
|
|
if error != AllocatorError.None {
|
|
ensure(false, "Failed to allocate entry to hashtable")
|
|
continue
|
|
}
|
|
lookup.queued = true
|
|
}
|
|
else {
|
|
lookup.captures = to_enqueue.captures
|
|
lookup.builder = to_enqueue.builder
|
|
lookup.queued = true
|
|
continue
|
|
}
|
|
|
|
if first == nil {
|
|
first = lookup
|
|
last = lookup
|
|
continue
|
|
}
|
|
last.next = lookup
|
|
last = lookup
|
|
}
|
|
array_clear(build_queue)
|
|
|
|
for entry := first; entry != nil; entry = entry.next
|
|
{
|
|
using entry
|
|
if ! queued
|
|
{
|
|
if entry == first
|
|
{
|
|
first = entry.next
|
|
entry.next = nil
|
|
continue
|
|
}
|
|
if entry == last
|
|
{
|
|
last = last.prev
|
|
last.prev = nil
|
|
entry.prev = nil
|
|
continue
|
|
}
|
|
|
|
left := entry.prev
|
|
right := entry.next
|
|
|
|
left.next = right
|
|
right.prev = left
|
|
entry.prev = nil
|
|
entry.next = nil
|
|
}
|
|
|
|
if builder( captures ) && entry != last
|
|
{
|
|
PopEntry:
|
|
{
|
|
if first == nil {
|
|
first = entry
|
|
last = entry
|
|
break PopEntry
|
|
}
|
|
if entry == first
|
|
{
|
|
first = entry.next
|
|
entry.next = nil
|
|
break PopEntry
|
|
}
|
|
if entry == last
|
|
{
|
|
last = last.prev
|
|
last.prev = nil
|
|
entry.prev = nil
|
|
break PopEntry
|
|
}
|
|
|
|
left := entry.prev
|
|
right := entry.next
|
|
|
|
left.next = right
|
|
right.prev = left
|
|
}
|
|
|
|
last.next = entry
|
|
last = entry
|
|
}
|
|
queued = false
|
|
}
|
|
}
|