2024-02-12 17:52:56 -08:00
|
|
|
package sectr
|
|
|
|
|
|
|
|
// TODO(Ed) : This is in Raddbg base_types.h, consider moving outside of UI.
|
2024-02-22 18:19:29 -08:00
|
|
|
Axis2 :: enum i32 {
|
|
|
|
Invalid = -1,
|
|
|
|
X = 0,
|
|
|
|
Y = 1,
|
2024-02-12 17:52:56 -08:00
|
|
|
Count,
|
|
|
|
}
|
|
|
|
|
2024-02-22 18:19:29 -08:00
|
|
|
Corner :: enum i32 {
|
|
|
|
Invalid = -1,
|
|
|
|
_00,
|
|
|
|
_01,
|
|
|
|
_10,
|
|
|
|
_11,
|
|
|
|
TopLeft = _00,
|
|
|
|
TopRight = _01,
|
|
|
|
BottomLeft = _10,
|
|
|
|
BottomRight = _11,
|
|
|
|
Count = 4,
|
2024-02-13 23:27:40 -08:00
|
|
|
}
|
|
|
|
|
2024-02-22 18:19:29 -08:00
|
|
|
Range2 :: struct #raw_union{
|
|
|
|
using _ : struct {
|
|
|
|
min, max : Vec2
|
|
|
|
},
|
|
|
|
using _ : struct {
|
|
|
|
p0, p1 : Vec2
|
|
|
|
},
|
|
|
|
using _ : struct {
|
|
|
|
x0, y0 : f32,
|
|
|
|
x1, y1 : f32,
|
|
|
|
},
|
2024-02-13 14:16:39 -08:00
|
|
|
}
|
|
|
|
|
2024-02-22 18:19:29 -08:00
|
|
|
Rect :: struct {
|
|
|
|
top_left, bottom_right : Vec2
|
|
|
|
}
|
|
|
|
|
|
|
|
Side :: enum i32 {
|
|
|
|
Invalid = -1,
|
|
|
|
Min = 0,
|
|
|
|
Max = 1,
|
|
|
|
Count
|
|
|
|
}
|
|
|
|
|
|
|
|
// Side2 :: enum u32 {
|
|
|
|
// Top,
|
|
|
|
// Bottom,
|
|
|
|
// Left,
|
|
|
|
// Right,
|
|
|
|
// Count,
|
|
|
|
// }
|
|
|
|
|
|
|
|
UI_AnchorPresets :: enum u32 {
|
|
|
|
Top_Left,
|
|
|
|
Top_Right,
|
|
|
|
Bottom_Right,
|
|
|
|
Bottom_Left,
|
|
|
|
Center_Left,
|
|
|
|
Center_Top,
|
|
|
|
Center_Right,
|
|
|
|
Center_Bottom,
|
|
|
|
Center,
|
|
|
|
Left_Wide,
|
|
|
|
Top_Wide,
|
|
|
|
Right_Wide,
|
|
|
|
Bottom_Wide,
|
|
|
|
VCenter_Wide,
|
|
|
|
HCenter_Wide,
|
|
|
|
Full,
|
2024-02-13 23:27:40 -08:00
|
|
|
Count,
|
|
|
|
}
|
|
|
|
|
2024-02-22 18:19:29 -08:00
|
|
|
UI_BoxFlag :: enum u64 {
|
|
|
|
Focusable,
|
2024-02-13 23:27:40 -08:00
|
|
|
|
2024-02-22 18:19:29 -08:00
|
|
|
Mouse_Clickable,
|
|
|
|
Keyboard_Clickable,
|
|
|
|
Click_To_Focus,
|
2024-02-13 23:27:40 -08:00
|
|
|
|
2024-02-22 18:19:29 -08:00
|
|
|
Fixed_With,
|
|
|
|
Fixed_Height,
|
2024-02-12 17:52:56 -08:00
|
|
|
|
2024-02-22 18:19:29 -08:00
|
|
|
Text_Wrap,
|
2024-02-12 17:52:56 -08:00
|
|
|
|
2024-02-22 18:19:29 -08:00
|
|
|
Count,
|
2024-02-12 17:52:56 -08:00
|
|
|
}
|
2024-02-22 18:19:29 -08:00
|
|
|
UI_BoxFlags :: bit_set[UI_BoxFlag; u64]
|
2024-02-12 17:52:56 -08:00
|
|
|
|
2024-02-22 18:19:29 -08:00
|
|
|
// The UI_Box's actual positioning and sizing
|
|
|
|
// There is an excess of rectangles here for debug puproses.
|
|
|
|
UI_Computed :: struct {
|
|
|
|
bounds : Range2,
|
|
|
|
border : Range2,
|
|
|
|
margin : Range2,
|
|
|
|
padding : Range2,
|
|
|
|
content : Range2,
|
2024-02-12 17:52:56 -08:00
|
|
|
}
|
|
|
|
|
2024-02-22 18:19:29 -08:00
|
|
|
UI_LayoutSide :: struct #raw_union {
|
|
|
|
using _ : struct {
|
|
|
|
top, bottom : UI_Scalar2,
|
|
|
|
left, right : UI_Scalar2,
|
|
|
|
}
|
2024-02-12 17:52:56 -08:00
|
|
|
}
|
|
|
|
|
2024-02-22 18:19:29 -08:00
|
|
|
UI_Cursor :: struct {
|
|
|
|
placeholder : int,
|
2024-02-12 17:52:56 -08:00
|
|
|
}
|
|
|
|
|
2024-02-22 18:19:29 -08:00
|
|
|
UI_Key :: distinct u64
|
2024-02-12 17:52:56 -08:00
|
|
|
|
2024-02-22 18:19:29 -08:00
|
|
|
UI_Scalar :: f32
|
2024-02-12 17:52:56 -08:00
|
|
|
|
2024-02-22 18:19:29 -08:00
|
|
|
// TODO(Ed): I'm not sure if Percentage is needed or if this would over complicate things...
|
|
|
|
// UI_Scalar :: struct {
|
|
|
|
// VPixels : f32,
|
|
|
|
// Percentage : f32,
|
|
|
|
// }
|
2024-02-12 17:52:56 -08:00
|
|
|
|
2024-02-22 18:19:29 -08:00
|
|
|
UI_ScalarConstraint :: struct {
|
|
|
|
min, max : UI_Scalar,
|
|
|
|
}
|
2024-02-12 17:52:56 -08:00
|
|
|
|
2024-02-22 18:19:29 -08:00
|
|
|
UI_Scalar2 :: [Axis2.Count]UI_Scalar
|
2024-02-12 17:52:56 -08:00
|
|
|
|
2024-02-22 18:19:29 -08:00
|
|
|
// Desiered constraints on the UI_Box.
|
|
|
|
UI_Layout :: struct {
|
|
|
|
// TODO(Ed) : Make sure this is all we need to represent an anchor.
|
|
|
|
anchor : Range2,
|
2024-02-13 14:16:39 -08:00
|
|
|
|
2024-02-22 18:19:29 -08:00
|
|
|
border_width : UI_Scalar,
|
2024-02-12 17:52:56 -08:00
|
|
|
|
2024-02-22 18:19:29 -08:00
|
|
|
margins : UI_LayoutSide,
|
|
|
|
padding : UI_LayoutSide,
|
2024-02-12 17:52:56 -08:00
|
|
|
|
2024-02-22 18:19:29 -08:00
|
|
|
corner_radii : [Corner.Count]f32,
|
2024-02-12 17:52:56 -08:00
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
// TODO(Ed) : Add support for this
|
|
|
|
size_to_content : b32,
|
|
|
|
size : Vec2,
|
|
|
|
}
|
2024-02-22 20:15:29 -08:00
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
UI_BoxState :: enum {
|
|
|
|
Disabled,
|
|
|
|
Default,
|
|
|
|
Hovered,
|
|
|
|
Focused,
|
2024-02-12 17:52:56 -08:00
|
|
|
}
|
|
|
|
|
2024-02-22 18:19:29 -08:00
|
|
|
UI_Style :: struct {
|
2024-02-27 04:50:57 -08:00
|
|
|
bg_color : Color,
|
|
|
|
border_color : Color,
|
|
|
|
|
|
|
|
blur_size : f32,
|
2024-02-12 17:52:56 -08:00
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
font : FontID,
|
|
|
|
font_size : f32,
|
|
|
|
text_color : Color,
|
|
|
|
text_alignment : UI_TextAlign,
|
2024-02-12 17:52:56 -08:00
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
cursor : UI_Cursor,
|
|
|
|
|
|
|
|
layout : UI_Layout,
|
2024-02-12 17:52:56 -08:00
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
transition_time : f32,
|
2024-02-12 17:52:56 -08:00
|
|
|
}
|
|
|
|
|
2024-02-22 18:19:29 -08:00
|
|
|
UI_TextAlign :: enum u32 {
|
|
|
|
Left,
|
|
|
|
Center,
|
|
|
|
Right,
|
|
|
|
Count
|
2024-02-12 17:52:56 -08:00
|
|
|
}
|
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
UI_InteractState :: struct {
|
|
|
|
hot_time : f32,
|
|
|
|
active_time : f32,
|
|
|
|
disabled_time : f32,
|
|
|
|
}
|
2024-02-12 17:52:56 -08:00
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
UI_Box :: struct {
|
|
|
|
// Cache ID
|
2024-02-22 18:19:29 -08:00
|
|
|
key : UI_Key,
|
|
|
|
label : string,
|
2024-02-12 17:52:56 -08:00
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
// Regenerated per frame.
|
|
|
|
first, last, prev, next, parent : ^ UI_Box,
|
|
|
|
num_children : i32,
|
2024-02-12 17:52:56 -08:00
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
flags : UI_BoxFlags,
|
|
|
|
computed : UI_Computed,
|
|
|
|
style : UI_Style,
|
2024-02-12 17:52:56 -08:00
|
|
|
|
2024-02-22 18:19:29 -08:00
|
|
|
// Persistent Data
|
2024-02-27 04:50:57 -08:00
|
|
|
// prev_computed : UI_Computed,
|
|
|
|
// prev_style : UI_Style,
|
|
|
|
mouse : UI_InteractState,
|
|
|
|
keyboard : UI_InteractState,
|
2024-02-12 17:52:56 -08:00
|
|
|
}
|
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
UI_Layout_Stack_Size :: 512
|
|
|
|
UI_Style_Stack_Size :: 512
|
|
|
|
UI_Parent_Stack_Size :: 1024
|
|
|
|
UI_Built_Boxes_Array_Size :: Kilobyte * 8
|
|
|
|
|
|
|
|
UI_FramePassKind :: enum {
|
|
|
|
Generate,
|
|
|
|
Compute,
|
|
|
|
Logical,
|
|
|
|
}
|
2024-02-22 20:15:29 -08:00
|
|
|
|
2024-02-22 18:19:29 -08:00
|
|
|
UI_State :: struct {
|
2024-02-27 04:50:57 -08:00
|
|
|
// TODO(Ed) : Use these
|
|
|
|
build_arenas : [2]Arena,
|
|
|
|
build_arena : ^ Arena,
|
|
|
|
|
|
|
|
built_box_count : i32,
|
|
|
|
|
|
|
|
caches : [2] HMapZPL( UI_Box ),
|
|
|
|
prev_cache : ^ HMapZPL( UI_Box ),
|
|
|
|
curr_cache : ^ HMapZPL( UI_Box ),
|
2024-02-12 17:52:56 -08:00
|
|
|
|
2024-02-22 20:15:29 -08:00
|
|
|
root : ^ UI_Box,
|
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
// Do we need to recompute the layout?
|
2024-02-22 20:15:29 -08:00
|
|
|
layout_dirty : b32,
|
2024-02-22 18:19:29 -08:00
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
// TODO(Ed) : Look into using a build arena like Ryan does for these possibly (and thus have a linked-list stack)
|
|
|
|
style_stack : Stack( UI_Style, UI_Style_Stack_Size ),
|
|
|
|
parent_stack : Stack( ^ UI_Box, UI_Parent_Stack_Size ),
|
|
|
|
|
|
|
|
hot : UI_Key,
|
|
|
|
active : UI_Key,
|
|
|
|
clipboard_copy : UI_Key,
|
|
|
|
last_clicked : UI_Key,
|
2024-02-22 18:19:29 -08:00
|
|
|
|
|
|
|
drag_start_mouse : Vec2,
|
|
|
|
// drag_state_arena : ^ Arena,
|
|
|
|
// drag_state data : string,
|
2024-02-27 04:50:57 -08:00
|
|
|
|
2024-02-12 17:52:56 -08:00
|
|
|
}
|
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
ui_key_from_string :: proc( value : string ) -> UI_Key {
|
2024-02-22 20:15:29 -08:00
|
|
|
key := cast(UI_Key) crc32( transmute([]byte) value )
|
|
|
|
return key
|
|
|
|
}
|
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
ui_box_equal :: proc( a, b : ^ UI_Box ) -> b32 {
|
2024-02-22 20:15:29 -08:00
|
|
|
BoxSize :: size_of(UI_Box)
|
2024-02-27 04:50:57 -08:00
|
|
|
|
|
|
|
result : b32 = true
|
|
|
|
result &= a.key == b.key // We assume for now the label is the same as the key, if not something is terribly wrong.
|
|
|
|
result &= a.flags == b.flags
|
|
|
|
|
2024-02-22 20:15:29 -08:00
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
ui_startup :: proc( ui : ^ UI_State, cache_allocator : Allocator )
|
|
|
|
{
|
2024-02-22 20:15:29 -08:00
|
|
|
ui := ui
|
|
|
|
ui^ = {}
|
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
for cache in (& ui.caches) {
|
|
|
|
box_cache, allocation_error := zpl_hmap_init_reserve( UI_Box, cache_allocator, UI_Built_Boxes_Array_Size )
|
|
|
|
verify( allocation_error == AllocatorError.None, "Failed to allocate box cache" )
|
|
|
|
cache = box_cache
|
|
|
|
}
|
|
|
|
|
|
|
|
ui.curr_cache = & ui.caches[1]
|
|
|
|
ui.prev_cache = & ui.caches[0]
|
2024-02-22 20:15:29 -08:00
|
|
|
}
|
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
ui_reload :: proc( ui : ^ UI_State, cache_allocator : Allocator )
|
|
|
|
{
|
2024-02-22 20:15:29 -08:00
|
|
|
// We need to repopulate Allocator references
|
2024-02-27 04:50:57 -08:00
|
|
|
for cache in & ui.caches {
|
|
|
|
cache.entries.allocator = cache_allocator
|
|
|
|
cache.hashes.allocator = cache_allocator
|
|
|
|
}
|
2024-02-22 20:15:29 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// TODO(Ed) : Is this even needed?
|
2024-02-27 04:50:57 -08:00
|
|
|
ui_shutdown :: proc() {
|
|
|
|
}
|
|
|
|
|
|
|
|
ui_graph_build_begin :: proc( ui : ^ UI_State, bounds : Vec2 = {} )
|
|
|
|
{
|
|
|
|
get_state().ui_context = ui
|
|
|
|
using get_state().ui_context
|
|
|
|
|
|
|
|
swap( & curr_cache, & prev_cache )
|
|
|
|
|
|
|
|
root = ui_box_make( {}, "root#001" )
|
|
|
|
ui_parent_push(root)
|
|
|
|
|
|
|
|
log("BUILD GRAPH BEGIN")
|
2024-02-22 20:15:29 -08:00
|
|
|
}
|
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
// TODO(Ed) :: Is this even needed?
|
|
|
|
ui_graph_build_end :: proc()
|
2024-02-22 20:15:29 -08:00
|
|
|
{
|
2024-02-27 04:50:57 -08:00
|
|
|
ui_parent_pop()
|
|
|
|
|
|
|
|
// Regenerate the computed layout if dirty
|
|
|
|
// ui_compute_layout()
|
|
|
|
|
|
|
|
get_state().ui_context = nil
|
|
|
|
log("BUILD GRAPH END")
|
|
|
|
}
|
|
|
|
|
|
|
|
@(deferred_none = ui_graph_build_end)
|
|
|
|
ui_graph_build :: proc( ui : ^ UI_State ) {
|
|
|
|
ui_graph_build_begin( ui )
|
|
|
|
}
|
|
|
|
|
|
|
|
ui_parent_push :: proc( ui : ^ UI_Box ) {
|
|
|
|
stack := & get_state().ui_context.parent_stack
|
|
|
|
stack_push( & get_state().ui_context.parent_stack, ui )
|
|
|
|
}
|
2024-02-22 20:15:29 -08:00
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
ui_parent_pop :: proc() {
|
|
|
|
// If size_to_content is set, we need to compute the layout now.
|
2024-02-22 20:15:29 -08:00
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
// Check to make sure that the parent's children are the same for this frame,
|
|
|
|
// if its not we need to mark the layout as dirty.
|
2024-02-22 20:15:29 -08:00
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
stack_pop( & get_state().ui_context.parent_stack )
|
|
|
|
}
|
|
|
|
|
|
|
|
@(deferred_none = ui_parent_pop)
|
|
|
|
ui_parent :: proc( ui : ^ UI_Box) {
|
|
|
|
ui_parent_push( ui )
|
|
|
|
}
|
|
|
|
|
|
|
|
ui_box_make :: proc( flags : UI_BoxFlags, label : string ) -> (^ UI_Box)
|
|
|
|
{
|
|
|
|
using get_state().ui_context
|
|
|
|
|
|
|
|
key := ui_key_from_string( label )
|
|
|
|
|
|
|
|
curr_box : (^ UI_Box)
|
|
|
|
prev_box := zpl_hmap_get( prev_cache, cast(u64) key )
|
|
|
|
{
|
|
|
|
set_result : ^ UI_Box
|
|
|
|
set_error : AllocatorError
|
|
|
|
if prev_box != nil {
|
|
|
|
// Previous history was found, copy over previous state.
|
|
|
|
set_result, set_error = zpl_hmap_set( curr_cache, cast(u64) key, (prev_box ^) )
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
box : UI_Box
|
|
|
|
box.key = key
|
|
|
|
box.label = label
|
|
|
|
set_result, set_error = zpl_hmap_set( curr_cache, cast(u64) key, box )
|
|
|
|
}
|
|
|
|
|
|
|
|
verify( set_error == AllocatorError.None, "Failed to set zpl_hmap due to allocator error" )
|
|
|
|
curr_box = set_result
|
|
|
|
}
|
|
|
|
|
|
|
|
if prev_box != nil {
|
|
|
|
layout_dirty &= ! ui_box_equal( curr_box, prev_box )
|
2024-02-22 20:15:29 -08:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
layout_dirty = true
|
|
|
|
}
|
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
curr_box.flags = flags
|
|
|
|
curr_box.style = ( stack_peek( & style_stack ) ^ )
|
|
|
|
curr_box.parent = ( stack_peek( & parent_stack ) ^ )
|
2024-02-22 20:15:29 -08:00
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
// If there is a parent, setup the relevant references
|
|
|
|
if curr_box.parent != nil
|
|
|
|
{
|
|
|
|
// dbl_linked_list_push_back( box.parent, nil, box )
|
|
|
|
curr_box.parent.last = curr_box
|
2024-02-22 20:15:29 -08:00
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
if curr_box.parent.first == nil {
|
|
|
|
curr_box.parent.first = curr_box
|
|
|
|
}
|
|
|
|
}
|
2024-02-22 20:15:29 -08:00
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
return curr_box
|
2024-02-12 17:52:56 -08:00
|
|
|
}
|
2024-02-22 20:15:29 -08:00
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
ui_set_layout :: proc ( layout : UI_Layout ) {
|
|
|
|
log("LAYOUT SET")
|
2024-02-22 20:15:29 -08:00
|
|
|
}
|
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
ui_compute_layout :: proc() {
|
|
|
|
// TODO(Ed) : This generates the bounds for each box.
|
|
|
|
}
|
2024-02-22 20:15:29 -08:00
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
ui_layout_set_size :: proc( size : Vec2 ) {
|
2024-02-22 20:15:29 -08:00
|
|
|
}
|
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
ui_style_push :: proc( preset : UI_Style ) {
|
|
|
|
log("STYLE PUSH")
|
|
|
|
stack_push( & get_state().ui_context.style_stack, preset )
|
|
|
|
}
|
2024-02-22 20:15:29 -08:00
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
ui_style_pop :: proc() {
|
|
|
|
log("STYLE POP")
|
|
|
|
stack_pop( & get_state().ui_context.style_stack )
|
2024-02-22 20:15:29 -08:00
|
|
|
}
|
|
|
|
|
2024-02-27 04:50:57 -08:00
|
|
|
@(deferred_none = ui_style_pop)
|
|
|
|
ui_style :: proc( preset : UI_Style ) {
|
|
|
|
ui_style_push( preset )
|
2024-02-22 20:15:29 -08:00
|
|
|
}
|