SectrPrototype/code/ui_floating.odin
Ed_ 85cf9d8db2 More progress on themes + workspace resize handles support
Still need to add support for centered resize of boxes with the handles. (Will need a different alignment configuration)

Theme manipulation is getting cleaned up iteratively code is slowly looking less nosiy
2024-05-15 18:48:20 -04:00

178 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 : HMapChainedPtr(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 = hmap_chained_init(UI_Floating, uint(tracked_cap), allocator, dbg_name = tracked_dbg_name.str )
if error != AllocatorError.None
{
ensure(false, "Failed to allocate tracking table")
return error
}
return error
}
ui_floating_reload :: proc( self : ^UI_FloatingManager, allocator : Allocator )
{
using self
build_queue.backing = allocator
hmap_chained_reload(tracked, allocator)
}
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()
using floating := get_state().ui_floating_context
for to_enqueue in array_to_slice( build_queue)
{
key := ui_key_from_string(to_enqueue.label)
lookup := hmap_chained_get( tracked, transmute(u64) key )
// Check if entry is already present
if lookup != nil && (lookup.next != nil || lookup == last) {
lookup.captures = to_enqueue.captures
lookup.builder = to_enqueue.builder
lookup.queued = true
continue
}
if lookup == nil {
error : AllocatorError
lookup, error = hmap_chained_set( tracked, transmute(u64) key, to_enqueue )
if error != AllocatorError.None {
ensure(false, "Failed to allocate entry to hashtable")
continue
}
}
else {
lookup.captures = to_enqueue.captures
lookup.builder = to_enqueue.builder
}
lookup.queued = true
if first == nil {
first = lookup
last = lookup
continue
}
if first == last {
last = lookup
last.prev = first
first.next = last
continue
}
last.next = lookup
lookup.prev = last
last = lookup
}
array_clear(build_queue)
to_raise : ^UI_Floating
for entry := first; entry != nil; entry = entry.next
{
if ! entry.queued
{
ensure(false, "There should be no queue failures yet")
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 entry.builder( entry.captures ) && entry != last && to_raise == nil
{
to_raise = entry
}
entry.queued = false
}
if to_raise != nil
{
dll_full_pop( to_raise, floating )
dll_full_push_back( floating, to_raise, nil )
}
}