Some general refactors and compaction
Made a distinction from the "core" ui vs the rest of the ui that composes from there.
This commit is contained in:
parent
7250456db5
commit
5ceef39410
code
app_scratch.odinapp_serialize.odinapp_state.odinapp_ui_theme_default.odinengine_client_api.odinengine_render.odinengine_render_gl.odinengine_render_raylib.odinengine_render_text_raylib.odinengine_update.odin
gen
grime_context.odingrime_grime.odinproject_manual_serialization.odinui_core.odinui_core_box.odinui_core_layout.odinui_core_layout_compute.odinui_core_signal.odinui_core_style.odinui_floating.odinui_theme.odinui_widgets.odinscripts
toolchain
114
code/app_ui_theme_default.odin
Normal file
114
code/app_ui_theme_default.odin
Normal file
@ -0,0 +1,114 @@
|
||||
package sectr
|
||||
|
||||
/*
|
||||
UI Themes: Comprise of UI_Box's layout & style
|
||||
|
||||
Provides presets for themes and their interface for manipulating the combo stacks in UI_State in pairs
|
||||
*/
|
||||
// TODO(Ed): Eventually this will have a configuration wizard, and we'll save the presets
|
||||
|
||||
@(deferred_none = ui_theme_pop)
|
||||
ui_theme_btn_default :: proc()
|
||||
{
|
||||
@static theme : UI_Theme
|
||||
@static loaded : b32 = false
|
||||
if ! loaded
|
||||
{
|
||||
layout := UI_Layout {
|
||||
flags = {},
|
||||
anchor = range2({},{}),
|
||||
alignment = {0, 0},
|
||||
text_alignment = {0.5, 0.5},
|
||||
font_size = 16,
|
||||
margins = {0, 0, 0, 0},
|
||||
padding = {0, 0, 0, 0},
|
||||
border_width = 1,
|
||||
pos = {0, 0},
|
||||
size = range2({},{})
|
||||
}
|
||||
style := UI_Style {
|
||||
bg_color = Color_ThmDark_Btn_BG_Default,
|
||||
border_color = Color_ThmDark_Border_Default,
|
||||
corner_radii = {},
|
||||
blur_size = 0,
|
||||
font = get_state().default_font,
|
||||
text_color = Color_ThmDark_Text_Default,
|
||||
cursor = {},
|
||||
}
|
||||
layout_combo := to_ui_layout_combo(layout)
|
||||
style_combo := to_ui_style_combo(style)
|
||||
{
|
||||
using layout_combo.hot
|
||||
using style_combo.hot
|
||||
bg_color = Color_ThmDark_Btn_BG_Hot
|
||||
text_color = Color_ThmDark_Text_Hot
|
||||
margins = {2, 2, 2, 2}
|
||||
}
|
||||
{
|
||||
using layout_combo.active
|
||||
using style_combo.active
|
||||
bg_color = Color_ThmDark_Btn_BG_Active
|
||||
text_color = Color_ThmDark_Text_Active
|
||||
margins = {2, 2, 2, 2}
|
||||
}
|
||||
theme = UI_Theme {
|
||||
layout_combo, style_combo
|
||||
}
|
||||
loaded = true
|
||||
}
|
||||
ui_layout_push(theme.layout)
|
||||
ui_style_push(theme.style)
|
||||
}
|
||||
|
||||
@(deferred_none = ui_theme_pop)
|
||||
ui_theme_transparent :: proc()
|
||||
{
|
||||
@static theme : UI_Theme
|
||||
@static loaded : b32 = false
|
||||
if ! loaded || true
|
||||
{
|
||||
layout := UI_Layout {
|
||||
flags = {},
|
||||
anchor = range2({},{}),
|
||||
alignment = {0, 0},
|
||||
text_alignment = {0.0, 0.0},
|
||||
font_size = 16,
|
||||
margins = {0, 0, 0, 0},
|
||||
padding = {0, 0, 0, 0},
|
||||
border_width = 0,
|
||||
pos = {0, 0},
|
||||
size = range2({},{})
|
||||
}
|
||||
style := UI_Style {
|
||||
bg_color = Color_Transparent,
|
||||
border_color = Color_Transparent,
|
||||
corner_radii = {},
|
||||
blur_size = 0,
|
||||
font = get_state().default_font,
|
||||
text_color = Color_ThmDark_Text_Default,
|
||||
cursor = {},
|
||||
}
|
||||
|
||||
layout_combo := to_ui_layout_combo(layout)
|
||||
style_combo := to_ui_style_combo(style)
|
||||
{
|
||||
using layout_combo.disabled
|
||||
using style_combo.disabled
|
||||
}
|
||||
{
|
||||
using layout_combo.hot
|
||||
using style_combo.hot
|
||||
}
|
||||
{
|
||||
using layout_combo.active
|
||||
using style_combo.active
|
||||
}
|
||||
|
||||
theme = UI_Theme {
|
||||
layout_combo, style_combo
|
||||
}
|
||||
loaded = true
|
||||
}
|
||||
ui_layout_push(theme.layout)
|
||||
ui_style_push(theme.style)
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
package sectr
|
||||
|
||||
import rl "vendor:raylib"
|
||||
|
||||
|
||||
range2_to_rl_rect :: #force_inline proc "contextless"( range : Range2 ) -> rl.Rectangle
|
||||
{
|
||||
rect := rl.Rectangle {
|
||||
range.min.x,
|
||||
range.max.y,
|
||||
abs(range.max.x - range.min.x),
|
||||
abs(range.max.y - range.min.y),
|
||||
}
|
||||
return rect
|
||||
}
|
||||
|
||||
|
2
code/engine_render_gl.odin
Normal file
2
code/engine_render_gl.odin
Normal file
@ -0,0 +1,2 @@
|
||||
package sectr
|
||||
|
@ -4,6 +4,17 @@ import "core:fmt"
|
||||
|
||||
import rl "vendor:raylib"
|
||||
|
||||
range2_to_rl_rect :: #force_inline proc "contextless"( range : Range2 ) -> rl.Rectangle
|
||||
{
|
||||
rect := rl.Rectangle {
|
||||
range.min.x,
|
||||
range.max.y,
|
||||
abs(range.max.x - range.min.x),
|
||||
abs(range.max.y - range.min.y),
|
||||
}
|
||||
return rect
|
||||
}
|
||||
|
||||
draw_rectangle :: #force_inline proc "contextless" ( rect : rl.Rectangle, box : ^UI_RenderBoxInfo ) {
|
||||
using box
|
||||
if style.corner_radii[0] > 0 {
|
||||
@ -211,9 +222,9 @@ render_mode_screenspace :: proc ()
|
||||
render_screen_ui()
|
||||
|
||||
fps_msg := str_fmt_tmp( "FPS: %f", fps_avg)
|
||||
fps_msg_width := measure_text_size( fps_msg, default_font, 16.0, 0.0 ).x
|
||||
fps_msg_width := measure_text_size( fps_msg, default_font, 12.0, 0.0 ).x
|
||||
fps_msg_pos := screen_get_corners().top_right - { fps_msg_width, 0 } - { 5, 5 }
|
||||
debug_draw_text( fps_msg, fps_msg_pos, 16.0, color = rl.GREEN )
|
||||
debug_draw_text( fps_msg, fps_msg_pos, 12.0, color = rl.GREEN )
|
||||
|
||||
debug_text :: proc( format : string, args : ..any )
|
||||
{
|
||||
@ -232,7 +243,7 @@ render_mode_screenspace :: proc ()
|
||||
position.y -= debug.draw_debug_text_y
|
||||
|
||||
content := str_fmt_buffer( draw_text_scratch[:], format, ..args )
|
||||
debug_draw_text( content, position, 14.0 )
|
||||
debug_draw_text( content, position, 12.0 )
|
||||
|
||||
debug.draw_debug_text_y += 14
|
||||
}
|
||||
@ -293,7 +304,6 @@ render_mode_screenspace :: proc ()
|
||||
}
|
||||
|
||||
view := view_get_bounds()
|
||||
// debug_text("View Bounds (World): %v", view.pts )
|
||||
|
||||
debug.draw_debug_text_y = 14
|
||||
|
||||
@ -304,10 +314,6 @@ render_mode_screenspace :: proc ()
|
||||
0.5, -0.5, 0.0, 0.0, 1.0, 0.0, 1.0, // Vertex 2: Green
|
||||
0.0, 0.5, 0.0, 0.0, 0.0, 1.0, 1.0 // Vertex 3: Blue
|
||||
}
|
||||
|
||||
// Begin using the shader to draw
|
||||
// rl.BeginShaderMode(debug.proto_text_shader)
|
||||
// rl.EndShaderMode()
|
||||
}
|
||||
|
||||
// A non-zoomable static-view for ui
|
||||
@ -366,7 +372,6 @@ render_screen_ui :: proc()
|
||||
|
||||
line_thickness : f32 = 1
|
||||
|
||||
// profile_begin("rl.DrawRectangleRoundedLines: padding & content")
|
||||
if debug.draw_UI_padding_bounds && equal_range2(computed.content, computed.padding) {
|
||||
draw_rectangle_lines( rect_padding, & current, Color_Debug_UI_Padding_Bounds, line_thickness )
|
||||
}
|
||||
@ -376,16 +381,17 @@ render_screen_ui :: proc()
|
||||
|
||||
point_radius : f32 = 3
|
||||
|
||||
// profile_begin("circles")
|
||||
if debug.draw_ui_box_bounds_points
|
||||
{
|
||||
computed_size := computed.bounds.p1 - computed.bounds.p0
|
||||
// center := Vec2 {
|
||||
// render_bounds.p0.x + computed_size.x * 0.5,
|
||||
// render_bounds.p0.y - computed_size.y * 0.5,
|
||||
// }
|
||||
// rl.DrawCircleV( center, point_radius, Color_White )
|
||||
|
||||
if false
|
||||
{
|
||||
center := Vec2 {
|
||||
render_bounds.p0.x + computed_size.x * 0.5,
|
||||
render_bounds.p0.y - computed_size.y * 0.5,
|
||||
}
|
||||
rl.DrawCircleV( center, point_radius, Color_White )
|
||||
}
|
||||
rl.DrawCircleV( render_bounds.p0, point_radius, Color_Red )
|
||||
rl.DrawCircleV( render_bounds.p1, point_radius, Color_Blue )
|
||||
}
|
@ -150,7 +150,7 @@ else
|
||||
|
||||
// Raylib's equivalent doesn't take a length for the string (making it a pain in the ass)
|
||||
// So this is a 1:1 copy except it takes Odin strings
|
||||
measure_text_size :: proc( text : string, font : FontID, font_size := Font_Use_Default_Size, spacing : f32 ) -> Vec2
|
||||
measure_text_size_raylib :: proc( text : string, font : FontID, font_size := Font_Use_Default_Size, spacing : f32 ) -> Vec2
|
||||
{
|
||||
// profile(#procedure)
|
||||
px_size := math.round( points_to_pixels( font_size ) )
|
@ -0,0 +1 @@
|
||||
package genodin
|
@ -1,11 +1,5 @@
|
||||
package sectr
|
||||
|
||||
// GrimeContextExt :: struct {
|
||||
// dbg_name : string
|
||||
// }
|
||||
|
||||
// Global_Transient_Context : GrimeContextExt
|
||||
|
||||
context_ext :: proc( $ Type : typeid ) -> (^Type) {
|
||||
return cast(^Type) context.user_ptr
|
||||
}
|
||||
|
@ -99,13 +99,6 @@ import "thirdparty:backtrace"
|
||||
|
||||
#endregion("Import Aliases")
|
||||
|
||||
OS_Type :: type_of(ODIN_OS)
|
||||
|
||||
|
||||
swap :: proc( a, b : ^ $Type ) -> ( ^ Type, ^ Type ) {
|
||||
return b, a
|
||||
}
|
||||
|
||||
#region("Proc overload mappings")
|
||||
|
||||
// This has to be done on a per-module basis.
|
||||
@ -163,6 +156,10 @@ is_power_of_two :: proc {
|
||||
is_power_of_two_uintptr,
|
||||
}
|
||||
|
||||
measure_text_size :: proc {
|
||||
measure_text_size_raylib,
|
||||
}
|
||||
|
||||
mov_avg_exp :: proc {
|
||||
mov_avg_exp_f32,
|
||||
mov_avg_exp_f64,
|
||||
@ -279,6 +276,11 @@ to_ui_layout_side :: proc {
|
||||
to_ui_layout_side_vec2,
|
||||
}
|
||||
|
||||
ui_compute_layout :: proc {
|
||||
ui_core_compute_layout,
|
||||
ui_box_compute_layout,
|
||||
}
|
||||
|
||||
ui_floating :: proc {
|
||||
ui_floating_just_builder,
|
||||
ui_floating_with_capture,
|
||||
@ -316,3 +318,7 @@ wedge :: proc {
|
||||
}
|
||||
|
||||
#endregion("Proc overload mappings")
|
||||
|
||||
OS_Type :: type_of(ODIN_OS)
|
||||
|
||||
swap :: #force_inline proc( a, b : ^ $Type ) -> ( ^ Type, ^ Type ) { return b, a }
|
||||
|
@ -32,25 +32,25 @@ Side :: enum i32 {
|
||||
// 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,
|
||||
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,
|
||||
// Count,
|
||||
// }
|
||||
|
||||
UI_Cursor :: struct {
|
||||
placeholder : int,
|
||||
@ -136,8 +136,7 @@ ui_startup :: proc( ui : ^ UI_State, cache_allocator : Allocator /* , cache_rese
|
||||
ui := ui
|
||||
ui^ = {}
|
||||
|
||||
// cache.ref in ui.caches.ref
|
||||
for & cache in (& ui.caches) {
|
||||
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
|
||||
@ -155,7 +154,7 @@ ui_startup :: proc( ui : ^ UI_State, cache_allocator : Allocator /* , cache_rese
|
||||
ui_reload :: proc( ui : ^ UI_State, cache_allocator : Allocator )
|
||||
{
|
||||
// We need to repopulate Allocator references
|
||||
for & cache in & ui.caches {
|
||||
for & cache in ui.caches {
|
||||
zpl_hmap_reload( & cache, cache_allocator)
|
||||
}
|
||||
ui.render_queue.backing = cache_allocator
|
||||
@ -180,11 +179,6 @@ ui_drag_delta :: #force_inline proc "contextless" () -> Vec2 {
|
||||
return ui_cursor_pos() - state.ui_context.active_start_signal.cursor_pos
|
||||
}
|
||||
|
||||
ui_ws_drag_delta :: #force_inline proc "contextless" () -> Vec2 {
|
||||
using state := get_state()
|
||||
return screen_to_ws_view_pos(input.mouse.pos) - state.ui_context.active_start_signal.cursor_pos
|
||||
}
|
||||
|
||||
ui_graph_build_begin :: proc( ui : ^ UI_State, bounds : Vec2 = {} )
|
||||
{
|
||||
profile(#procedure)
|
||||
@ -197,10 +191,7 @@ ui_graph_build_begin :: proc( ui : ^ UI_State, bounds : Vec2 = {} )
|
||||
stack_clear( & style_combo_stack )
|
||||
array_clear( render_queue )
|
||||
|
||||
temp := prev_cache
|
||||
prev_cache = curr_cache
|
||||
curr_cache = temp
|
||||
// curr_cache, prev_cache = swap( curr_cache, prev_cache )
|
||||
curr_cache, prev_cache = swap( curr_cache, prev_cache )
|
||||
|
||||
if ui.active == UI_Key(0) {
|
||||
//ui.hot = UI_Key(0)
|
||||
@ -228,9 +219,7 @@ ui_graph_build_end :: proc( ui : ^UI_State )
|
||||
}
|
||||
|
||||
@(deferred_in = ui_graph_build_end)
|
||||
ui_graph_build :: proc( ui : ^ UI_State ) {
|
||||
ui_graph_build_begin( ui )
|
||||
}
|
||||
ui_graph_build :: #force_inline proc( ui : ^ UI_State ) { ui_graph_build_begin( ui ) }
|
||||
|
||||
ui_key_from_string :: #force_inline proc "contextless" ( value : string ) -> UI_Key
|
||||
{
|
||||
@ -254,26 +243,13 @@ ui_key_from_string :: #force_inline proc "contextless" ( value : string ) -> UI_
|
||||
return key
|
||||
}
|
||||
|
||||
ui_parent_push :: proc( ui : ^ UI_Box ) {
|
||||
stack := & get_state().ui_context.parent_stack
|
||||
stack_push( & get_state().ui_context.parent_stack, ui )
|
||||
}
|
||||
|
||||
ui_parent_pop :: proc() {
|
||||
// If size_to_content is set, we need to compute the layout now.
|
||||
|
||||
// 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.
|
||||
|
||||
stack_pop( & get_state().ui_context.parent_stack )
|
||||
}
|
||||
ui_parent_push :: #force_inline proc( ui : ^ UI_Box ) { stack_push( & ui_context().parent_stack, ui ) }
|
||||
ui_parent_pop :: #force_inline proc() { stack_pop( & get_state().ui_context.parent_stack ) }
|
||||
|
||||
@(deferred_none = ui_parent_pop)
|
||||
ui_parent :: #force_inline proc( ui : ^UI_Box) { ui_parent_push( ui ) }
|
||||
|
||||
ui_prev_cached_box :: #force_inline proc( box : ^UI_Box ) -> ^UI_Box {
|
||||
return zpl_hmap_get( ui_context().prev_cache, cast(u64) box.key )
|
||||
}
|
||||
ui_prev_cached_box :: #force_inline proc( box : ^UI_Box ) -> ^UI_Box { return zpl_hmap_get( ui_context().prev_cache, cast(u64) box.key ) }
|
||||
|
||||
// Topmost ancestor that is not the root
|
||||
ui_top_ancestor :: #force_inline proc "contextless" ( box : ^UI_Box ) -> (^UI_Box) {
|
@ -1,6 +1,7 @@
|
||||
package sectr
|
||||
|
||||
UI_BoxFlag :: enum u64 {
|
||||
UI_BoxFlag :: enum u64
|
||||
{
|
||||
Disabled,
|
||||
|
||||
Focusable,
|
||||
@ -9,13 +10,6 @@ UI_BoxFlag :: enum u64 {
|
||||
Mouse_Clickable,
|
||||
Keyboard_Clickable,
|
||||
|
||||
// Pan_X,
|
||||
// Pan_Y,
|
||||
|
||||
// Scroll_X,
|
||||
// Scroll_Y,
|
||||
|
||||
// Screenspace,
|
||||
Count,
|
||||
}
|
||||
UI_BoxFlags :: bit_set[UI_BoxFlag; u64]
|
||||
@ -24,9 +18,9 @@ UI_BoxFlags :: bit_set[UI_BoxFlag; u64]
|
||||
UI_RenderBoxInfo :: struct {
|
||||
using computed : UI_Computed,
|
||||
using style : UI_Style,
|
||||
text : StrRunesPair,
|
||||
font_size : UI_Scalar,
|
||||
border_width : UI_Scalar,
|
||||
text : StrRunesPair,
|
||||
font_size : UI_Scalar,
|
||||
border_width : UI_Scalar,
|
||||
}
|
||||
|
||||
UI_Box :: struct {
|
||||
@ -60,8 +54,6 @@ UI_Box :: struct {
|
||||
first_frame : b8,
|
||||
// root_order_id : i16,
|
||||
|
||||
// prev_computed : UI_Computed,
|
||||
// prev_style : UI_Style,v
|
||||
// mouse : UI_InteractState,
|
||||
// keyboard : UI_InteractState,
|
||||
}
|
||||
@ -82,16 +74,13 @@ ui_box_from_key :: #force_inline proc ( cache : ^HMapZPL(UI_Box), key : UI_Key )
|
||||
ui_box_make :: proc( flags : UI_BoxFlags, label : string ) -> (^ UI_Box)
|
||||
{
|
||||
// profile(#procedure)
|
||||
|
||||
using ui := get_state().ui_context
|
||||
|
||||
key := ui_key_from_string( label )
|
||||
|
||||
curr_box : (^ UI_Box)
|
||||
prev_box := zpl_hmap_get( prev_cache, cast(u64) key )
|
||||
{
|
||||
// profile("Assigning current box")
|
||||
|
||||
set_result : ^ UI_Box
|
||||
set_error : AllocatorError
|
||||
if prev_box != nil
|
||||
@ -103,18 +92,15 @@ ui_box_make :: proc( flags : UI_BoxFlags, label : string ) -> (^ UI_Box)
|
||||
box : UI_Box
|
||||
box.key = key
|
||||
box.label = str_intern( label )
|
||||
// set_result, set_error = zpl_hmap_set( prev_cache, cast(u64) key, box )
|
||||
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
|
||||
|
||||
curr_box = set_result
|
||||
curr_box.first_frame = prev_box == nil
|
||||
curr_box.flags = flags
|
||||
}
|
||||
|
||||
curr_box.flags = flags
|
||||
|
||||
// Clear non-persistent data
|
||||
curr_box.computed.fresh = false
|
||||
curr_box.links = {}
|
||||
@ -124,30 +110,7 @@ ui_box_make :: proc( flags : UI_BoxFlags, label : string ) -> (^ UI_Box)
|
||||
parent := stack_peek( & parent_stack )
|
||||
if parent != nil
|
||||
{
|
||||
when true {
|
||||
dll_full_push_back( parent, curr_box, nil )
|
||||
}
|
||||
else
|
||||
{
|
||||
// |
|
||||
// v
|
||||
// parent.first <nil>
|
||||
if parent.first == nil {
|
||||
parent.first = curr_box
|
||||
parent.last = curr_box
|
||||
curr_box.next = nil
|
||||
curr_box.prev = nil
|
||||
}
|
||||
else {
|
||||
// Positin is set to last, insert at end
|
||||
// <parent.last.prev> <parent.last> curr_box
|
||||
parent.last.next = curr_box
|
||||
curr_box.prev = parent.last
|
||||
parent.last = curr_box
|
||||
curr_box.next = nil
|
||||
}
|
||||
}
|
||||
|
||||
dll_full_push_back( parent, curr_box, nil )
|
||||
curr_box.parent_index = parent.num_children
|
||||
parent.num_children += 1
|
||||
curr_box.parent = parent
|
||||
@ -160,37 +123,31 @@ ui_box_make :: proc( flags : UI_BoxFlags, label : string ) -> (^ UI_Box)
|
||||
|
||||
ui_box_tranverse_next :: proc "contextless" ( box : ^ UI_Box ) -> (^ UI_Box)
|
||||
{
|
||||
// Check to make sure parent is present on the screen, if its not don't bother.
|
||||
// If current has children, do them first
|
||||
using state := get_state()
|
||||
// If current has children, do them first
|
||||
if box.first != nil
|
||||
{
|
||||
// Check to make sure parent is present on the screen, if its not don't bother.
|
||||
is_app_ui := ui_context == & screen_ui
|
||||
if is_app_ui || intersects_range2( view_get_bounds(), box.computed.bounds)
|
||||
if intersects_range2( view_get_bounds(), box.computed.bounds)
|
||||
{
|
||||
return box.first
|
||||
}
|
||||
}
|
||||
|
||||
if box.next == nil
|
||||
{
|
||||
// There is no more adjacent nodes
|
||||
if box.parent != nil
|
||||
{
|
||||
parent := box.parent
|
||||
// Attempt to find a parent with a next, otherwise we just return a parent with nil
|
||||
for ; parent.parent != nil;
|
||||
{
|
||||
if parent.next != nil {
|
||||
break
|
||||
}
|
||||
parent = parent.parent
|
||||
}
|
||||
if box.next != nil do return box.next
|
||||
// There is no more adjacent nodes
|
||||
|
||||
// Lift back up to parent, and set it to its next.
|
||||
return parent.next
|
||||
parent := box.parent
|
||||
// Attempt to find a parent with a next, otherwise we just return a parent with nil
|
||||
for ; parent.parent != nil;
|
||||
{
|
||||
if parent.next != nil {
|
||||
break
|
||||
}
|
||||
parent = parent.parent
|
||||
}
|
||||
|
||||
return box.next
|
||||
// Lift back up to parent, and set it to its next.
|
||||
return parent.next
|
||||
}
|
@ -76,7 +76,6 @@ UI_LayoutFlag :: enum u32 {
|
||||
Fixed_Width,
|
||||
Fixed_Height,
|
||||
|
||||
// TODO(Ed): Implement this!
|
||||
// Enforces the widget will have a width specified as a ratio of its height (use the size.min/max.x to specify the scalar)
|
||||
// If you wish for the width to stay fixed couple with the Fixed_Width flag
|
||||
Scale_Width_By_Height_Ratio,
|
||||
@ -96,6 +95,9 @@ UI_LayoutFlag :: enum u32 {
|
||||
Size_To_Text,
|
||||
|
||||
// TODO(Ed): Implement this!
|
||||
// ?Note(Ed): This can get pretty complicated... Maybe its better to leave this to composition of boxes.
|
||||
// ?A text wrapping panel can organize text and wrap it via procedrually generated lines in a hbox/vbox.
|
||||
// ?It would be a non-issue so long as the text rendering bottleneck is resolved.
|
||||
// Wrap text around the box, text_alignment specifies the justification for its compostion when wrapping.
|
||||
Text_Wrap,
|
||||
|
@ -8,26 +8,10 @@ ui_box_compute_layout :: proc( box : ^UI_Box,
|
||||
// profile("Layout Box")
|
||||
state := get_state()
|
||||
ui := state.ui_context
|
||||
|
||||
parent := box.parent
|
||||
|
||||
style := box.style
|
||||
layout := & box.layout
|
||||
|
||||
// These are used to choose via multiplication weather to apply
|
||||
// position & size constraints of the parent.
|
||||
// The parent's unadjusted content bounds however are enforced for position,
|
||||
// they cannot be ignored. The user may bypass them by doing the
|
||||
// relative offset math vs world/screen space if they desire.
|
||||
// fixed_pos_x : f32 = cast(f32) int(.Fixed_Position_X in layout.flags)
|
||||
// fixed_pos_y : f32 = cast(f32) int(.Fixed_Position_Y in layout.flags)
|
||||
// fixed_width : f32 = cast(f32) int(.Fixed_Width in layout.flags)
|
||||
// fixed_height : f32 = cast(f32) int(.Fixed_Height in layout.flags)
|
||||
using box
|
||||
|
||||
size_to_text : bool = .Size_To_Text in layout.flags
|
||||
|
||||
computed := & box.computed
|
||||
|
||||
parent_content := parent.computed.content
|
||||
parent_content_size := parent_content.max - parent_content.min
|
||||
parent_center := parent_content.min + parent_content_size * 0.5
|
||||
@ -98,6 +82,13 @@ ui_box_compute_layout :: proc( box : ^UI_Box,
|
||||
adjusted_size = text_size
|
||||
}
|
||||
|
||||
if .Scale_Width_By_Height_Ratio in layout.flags {
|
||||
adjusted_size.x = adjusted_size.y * layout.size.min.x
|
||||
}
|
||||
if .Scale_Height_By_Width_Ratio in layout.flags {
|
||||
adjusted_size.y = adjusted_size.x * layout.size.min.y
|
||||
}
|
||||
|
||||
if .Size_To_Content in layout.flags {
|
||||
// Preemtively traverse the children of this parent and have them compute their layout.
|
||||
// This parent will just set its size to the max bounding area of those children.
|
||||
@ -135,8 +126,7 @@ ui_box_compute_layout :: proc( box : ^UI_Box,
|
||||
// 6. Determine the box bounds
|
||||
// Adjust Alignment of pivot position
|
||||
alignment := layout.alignment
|
||||
bounds : Range2
|
||||
|
||||
bounds : Range2
|
||||
if ! (.Origin_At_Anchor_Center in layout.flags) {
|
||||
// The convention offset adjust the box so that the top-left point is at the top left of the anchor's bounds
|
||||
tl_convention_offset := adjusted_size * {0, -1}
|
||||
@ -153,6 +143,7 @@ ui_box_compute_layout :: proc( box : ^UI_Box,
|
||||
)
|
||||
}
|
||||
|
||||
// 7. Padding & Content
|
||||
// Determine Padding's outer bounds
|
||||
border_offset := Vec2 { layout.border_width, layout.border_width }
|
||||
|
||||
@ -167,21 +158,20 @@ ui_box_compute_layout :: proc( box : ^UI_Box,
|
||||
bounds.max - { layout.padding.right, layout.padding.top } - border_offset,
|
||||
)
|
||||
|
||||
computed.bounds = bounds
|
||||
computed.bounds = bounds
|
||||
computed.padding = padding_bounds
|
||||
computed.content = content_bounds
|
||||
|
||||
// 8. Text position & size
|
||||
if len(box.text.str) > 0
|
||||
{
|
||||
content_size := content_bounds.max - content_bounds.min
|
||||
text_pos : Vec2
|
||||
text_pos = content_bounds.min + { 0, text_size.y }
|
||||
// text_pos.x += ( content_size.x - text_size.x ) * layout.text_alignment.x
|
||||
// text_pos.y += ( content_size.y - text_size.y ) * layout.text_alignment.y
|
||||
text_pos += (content_size - text_size) * layout.text_alignment
|
||||
|
||||
computed.text_size = text_size
|
||||
computed.text_pos = { text_pos.x, text_pos.y }
|
||||
computed.text_pos = text_pos
|
||||
}
|
||||
computed.fresh = true && !dont_mark_fresh
|
||||
}
|
||||
@ -196,7 +186,7 @@ ui_box_compute_layout_children :: proc( box : ^UI_Box )
|
||||
}
|
||||
}
|
||||
|
||||
ui_compute_layout :: proc( ui : ^UI_State )
|
||||
ui_core_compute_layout :: proc( ui : ^UI_State )
|
||||
{
|
||||
profile(#procedure)
|
||||
state := get_state()
|
@ -116,20 +116,21 @@ ui_floating_build :: proc()
|
||||
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
|
||||
dll_full_push_back(floating, lookup, nil )
|
||||
// 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)
|
||||
|
||||
|
@ -35,116 +35,3 @@ ui_theme_via_theme :: #force_inline proc( theme : UI_Theme ) {
|
||||
ui_layout_push( theme.layout )
|
||||
ui_style_push( theme.style )
|
||||
}
|
||||
|
||||
/*
|
||||
UI Themes: Comprise of UI_Box's layout & style
|
||||
|
||||
Provides presets for themes and their interface for manipulating the combo stacks in UI_State in pairs
|
||||
*/
|
||||
// TODO(Ed): Eventually this will have a configuration wizard, and we'll save the presets
|
||||
|
||||
@(deferred_none = ui_theme_pop)
|
||||
ui_theme_btn_default :: proc()
|
||||
{
|
||||
@static theme : UI_Theme
|
||||
@static loaded : b32 = false
|
||||
if ! loaded
|
||||
{
|
||||
layout := UI_Layout {
|
||||
flags = {},
|
||||
anchor = range2({},{}),
|
||||
alignment = {0, 0},
|
||||
text_alignment = {0.5, 0.5},
|
||||
font_size = 16,
|
||||
margins = {0, 0, 0, 0},
|
||||
padding = {0, 0, 0, 0},
|
||||
border_width = 1,
|
||||
pos = {0, 0},
|
||||
size = range2({},{})
|
||||
}
|
||||
style := UI_Style {
|
||||
bg_color = Color_ThmDark_Btn_BG_Default,
|
||||
border_color = Color_ThmDark_Border_Default,
|
||||
corner_radii = {},
|
||||
blur_size = 0,
|
||||
font = get_state().default_font,
|
||||
text_color = Color_ThmDark_Text_Default,
|
||||
cursor = {},
|
||||
}
|
||||
layout_combo := to_ui_layout_combo(layout)
|
||||
style_combo := to_ui_style_combo(style)
|
||||
{
|
||||
using layout_combo.hot
|
||||
using style_combo.hot
|
||||
bg_color = Color_ThmDark_Btn_BG_Hot
|
||||
text_color = Color_ThmDark_Text_Hot
|
||||
margins = {2, 2, 2, 2}
|
||||
}
|
||||
{
|
||||
using layout_combo.active
|
||||
using style_combo.active
|
||||
bg_color = Color_ThmDark_Btn_BG_Active
|
||||
text_color = Color_ThmDark_Text_Active
|
||||
margins = {2, 2, 2, 2}
|
||||
}
|
||||
theme = UI_Theme {
|
||||
layout_combo, style_combo
|
||||
}
|
||||
loaded = true
|
||||
}
|
||||
ui_layout_push(theme.layout)
|
||||
ui_style_push(theme.style)
|
||||
}
|
||||
|
||||
@(deferred_none = ui_theme_pop)
|
||||
ui_theme_transparent :: proc()
|
||||
{
|
||||
@static theme : UI_Theme
|
||||
@static loaded : b32 = false
|
||||
if ! loaded || true
|
||||
{
|
||||
layout := UI_Layout {
|
||||
flags = {},
|
||||
anchor = range2({},{}),
|
||||
alignment = {0, 0},
|
||||
text_alignment = {0.0, 0.0},
|
||||
font_size = 16,
|
||||
margins = {0, 0, 0, 0},
|
||||
padding = {0, 0, 0, 0},
|
||||
border_width = 0,
|
||||
pos = {0, 0},
|
||||
size = range2({},{})
|
||||
}
|
||||
style := UI_Style {
|
||||
bg_color = Color_Transparent,
|
||||
border_color = Color_Transparent,
|
||||
corner_radii = {},
|
||||
blur_size = 0,
|
||||
font = get_state().default_font,
|
||||
text_color = Color_ThmDark_Text_Default,
|
||||
cursor = {},
|
||||
}
|
||||
|
||||
layout_combo := to_ui_layout_combo(layout)
|
||||
style_combo := to_ui_style_combo(style)
|
||||
{
|
||||
using layout_combo.disabled
|
||||
using style_combo.disabled
|
||||
}
|
||||
{
|
||||
using layout_combo.hot
|
||||
using style_combo.hot
|
||||
}
|
||||
{
|
||||
using layout_combo.active
|
||||
using style_combo.active
|
||||
}
|
||||
|
||||
theme = UI_Theme {
|
||||
layout_combo, style_combo
|
||||
}
|
||||
loaded = true
|
||||
}
|
||||
ui_layout_push(theme.layout)
|
||||
ui_style_push(theme.style)
|
||||
}
|
||||
|
@ -425,6 +425,18 @@ ui_spacer :: proc( label : string ) -> (widget : UI_Widget) {
|
||||
return
|
||||
}
|
||||
|
||||
// UI_ScrollBox {
|
||||
// using widget : UI_Widget,
|
||||
// scroll_bar : UI_Widget,
|
||||
// content : UI_Widget,
|
||||
// }
|
||||
|
||||
// ui_scroll_box :: proc( label : string ) -> (scroll_box : UI_ScrollBox) {
|
||||
|
||||
// }
|
||||
|
||||
// ui_scrollable_view( )
|
||||
|
||||
#region("Text")
|
||||
|
||||
ui_text :: proc( label : string, content : StrRunesPair, flags : UI_BoxFlags = {} ) -> UI_Widget
|
||||
@ -468,6 +480,8 @@ ui_text_tabs :: proc( label : string, flags : UI_BoxFlags = {} ) -> UI_Widget
|
||||
box.text = tab_str
|
||||
return { box, signal }
|
||||
}
|
||||
|
||||
ui_text_wrap_panel :: proc( label : string, flags : UI_BoxFlags = {} )
|
||||
#endregion("Text")
|
||||
|
||||
#region("Vertical Box")
|
||||
|
@ -38,12 +38,16 @@ foreach ($file in $files)
|
||||
}
|
||||
else
|
||||
{
|
||||
# For files without a namespace, create a symbolic link in the root of the original code's path in virtual view
|
||||
$linkPath = Join-Path $path_virtual_view $fileName
|
||||
if (-not (Test-Path $linkPath)) {
|
||||
New-Item -ItemType SymbolicLink -Path $linkPath -Value $file.FullName
|
||||
}
|
||||
}
|
||||
# For files without a namespace, maintain the directory structure in the virtual view
|
||||
$relativePath = $file.FullName.Substring($path_code.Length + 1)
|
||||
$linkPath = Join-Path $path_virtual_view $relativePath
|
||||
$linkDir = Split-Path -Parent $linkPath
|
||||
|
||||
if (-not (Test-Path $linkDir)) {
|
||||
New-Item -ItemType Directory -Path $linkDir -Force
|
||||
}
|
||||
New-Item -ItemType SymbolicLink -Path $linkPath -Value $file.FullName
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host "Virtual view created successfully."
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 0d4069d2ea7aaf155b8c5d979fbbc590360314d0
|
||||
Subproject commit 67ae530d22c116f86d476743b5dfc978255391d4
|
Loading…
Reference in New Issue
Block a user