Got "Line LODs" working for the whitespace AST test, first step toward hboxes
Yet another issue with memory persists (seems to be related to slab free)
This commit is contained in:
@ -91,8 +91,8 @@ startup :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem
|
||||
push( policy_ptr, SlabSizeClass { 2 * Megabyte, 256 * Kilobyte, alignment })
|
||||
push( policy_ptr, SlabSizeClass { 2 * Megabyte, 512 * Kilobyte, alignment })
|
||||
push( policy_ptr, SlabSizeClass { 2 * Megabyte, 1 * Megabyte, alignment })
|
||||
push( policy_ptr, SlabSizeClass { 2 * Megabyte, 2 * Megabyte, alignment })
|
||||
push( policy_ptr, SlabSizeClass { 4 * Megabyte, 4 * Megabyte, alignment })
|
||||
push( policy_ptr, SlabSizeClass { 2 * Megabyte, 2 * Megabyte, alignment })
|
||||
push( policy_ptr, SlabSizeClass { 4 * Megabyte, 4 * Megabyte, alignment })
|
||||
// push( policy_ptr, SlabSizeClass { 8 * Megabyte, 8 * Megabyte, alignment })
|
||||
// push( policy_ptr, SlabSizeClass { 16 * Megabyte, 16 * Megabyte, alignment })
|
||||
// push( policy_ptr, SlabSizeClass { 32 * Megabyte, 32 * Megabyte, alignment })
|
||||
@ -135,6 +135,8 @@ startup :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem
|
||||
|
||||
engine_refresh_hz = 30
|
||||
|
||||
timing_fps_moving_avg_alpha = 0.9
|
||||
|
||||
ui_resize_border_width = 5
|
||||
}
|
||||
|
||||
@ -359,6 +361,10 @@ tick :: proc( host_delta_time : f64, host_delta_ns : Duration ) -> b32
|
||||
}
|
||||
}
|
||||
|
||||
config.timing_fps_moving_avg_alpha = 0.99
|
||||
frametime_avg_ms = mov_avg_exp( f64(config.timing_fps_moving_avg_alpha), frametime_elapsed_ms, frametime_avg_ms )
|
||||
fps_avg = 1 / (frametime_avg_ms * MS_To_S)
|
||||
|
||||
if frametime_elapsed_ms > 60.0 {
|
||||
log( str_fmt_tmp("Big tick! %v ms", frametime_elapsed_ms), LogLevel.Warning )
|
||||
}
|
||||
|
@ -2,14 +2,23 @@ package sectr
|
||||
|
||||
import "core:math/linalg"
|
||||
|
||||
pos_within_range2 :: proc( pos : Vec2, range : Range2 ) -> b32 {
|
||||
within_x := pos.x > range.min.x && pos.x < range.max.x
|
||||
within_y := pos.y > range.min.y && pos.y < range.max.y
|
||||
return b32(within_x && within_y)
|
||||
// AABB: Separating Axis Theorem
|
||||
intersects_range2 :: #force_inline proc "contextless" ( a, b: Range2 ) -> bool
|
||||
{
|
||||
// Check if there's no overlap on the x-axis
|
||||
if a.max.x < b.min.x || b.max.x < a.min.x {
|
||||
return false; // No overlap on x-axis means no intersection
|
||||
}
|
||||
// Check if there's no overlap on the y-axis
|
||||
if a.max.y < b.min.y || b.max.y < a.min.y {
|
||||
return false; // No overlap on y-axis means no intersection
|
||||
}
|
||||
// If neither of the above conditions are true, there's at least a partial overlap
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO(Ed): Do we need this? Also does it even work (looks unfinished)?
|
||||
is_within_screenspace :: proc( pos : Vec2 ) -> b32 {
|
||||
is_within_screenspace :: #force_inline proc "contextless" ( pos : Vec2 ) -> b32 {
|
||||
state := get_state(); using state
|
||||
screen_extent := state.app_window.extent
|
||||
cam := & project.workspace.cam
|
||||
@ -18,13 +27,14 @@ is_within_screenspace :: proc( pos : Vec2 ) -> b32 {
|
||||
return within_x_bounds && within_y_bounds
|
||||
}
|
||||
|
||||
within_range2 :: #force_inline proc ( a, b : Range2 ) -> bool {
|
||||
a_half_size := size_range2( a ) * 0.5
|
||||
b_half_size := size_range2( b ) * 0.5
|
||||
a_center := a.p0 + { a_half_size.x, -a_half_size.y }
|
||||
b_center := b.p0 + { b_half_size.x, -b_half_size.y }
|
||||
|
||||
within_x := abs(a_center.x - b_center.x) <= (a_half_size.x + b_half_size.y)
|
||||
within_y := abs(a_center.y - b_center.y) <= (a_half_size.y + b_half_size.y)
|
||||
within_range2 :: #force_inline proc "contextless" ( a, b : Range2 ) -> bool {
|
||||
within_x := b.min.x >= a.min.x && b.max.x <= a.max.x
|
||||
within_y := b.min.y >= a.min.y && b.max.y <= a.max.y
|
||||
return within_x && within_y
|
||||
}
|
||||
|
||||
pos_within_range2 :: #force_inline proc "contextless" ( pos : Vec2, range : Range2 ) -> b32 {
|
||||
within_x := pos.x > range.min.x && pos.x < range.max.x
|
||||
within_y := pos.y > range.min.y && pos.y < range.max.y
|
||||
return b32(within_x && within_y)
|
||||
}
|
||||
|
@ -137,6 +137,8 @@ AppConfig :: struct {
|
||||
|
||||
engine_refresh_hz : uint,
|
||||
|
||||
timing_fps_moving_avg_alpha : f32,
|
||||
|
||||
ui_resize_border_width : f32,
|
||||
}
|
||||
|
||||
@ -169,12 +171,13 @@ State :: struct {
|
||||
|
||||
sleep_is_granular : b32,
|
||||
|
||||
frametime_delta_seconds : f64,
|
||||
frametime_delta_ms : f64,
|
||||
frametime_delta_ns : Duration,
|
||||
frametime_target_ms : f64,
|
||||
|
||||
frametime_elapsed_ms : f64,
|
||||
frametime_delta_seconds : f64,
|
||||
frametime_delta_ms : f64,
|
||||
frametime_delta_ns : Duration,
|
||||
frametime_target_ms : f64,
|
||||
frametime_elapsed_ms : f64,
|
||||
frametime_avg_ms : f64,
|
||||
fps_avg : f64,
|
||||
|
||||
font_firacode : FontID,
|
||||
font_squidgy_slimes : FontID,
|
||||
|
@ -104,6 +104,11 @@ draw_text :: proc {
|
||||
draw_text_string_cached,
|
||||
}
|
||||
|
||||
mov_avg_exp :: proc {
|
||||
mov_avg_exp_f32,
|
||||
mov_avg_exp_f64,
|
||||
}
|
||||
|
||||
get_bounds :: proc {
|
||||
view_get_bounds,
|
||||
}
|
||||
|
@ -82,7 +82,7 @@ zpl_hmap_destroy :: proc( using self : ^ HMapZPL( $ Type ) ) {
|
||||
}
|
||||
}
|
||||
|
||||
zpl_hmap_get :: proc( using self : ^ HMapZPL( $ Type ), key : u64 ) -> ^ Type
|
||||
zpl_hmap_get :: proc ( using self : ^ HMapZPL( $ Type ), key : u64 ) -> ^ Type
|
||||
{
|
||||
// profile(#procedure)
|
||||
id := zpl_hmap_find( self, key ).entry_index
|
||||
|
@ -7,11 +7,23 @@ Axis2 :: enum i32 {
|
||||
Count,
|
||||
}
|
||||
|
||||
is_power_of_two_u32 :: proc( value : u32 ) -> b32
|
||||
is_power_of_two_u32 :: #force_inline proc "contextless" ( value : u32 ) -> b32
|
||||
{
|
||||
return value != 0 && ( value & ( value - 1 )) == 0
|
||||
}
|
||||
|
||||
mov_avg_exp_f32 := #force_inline proc "contextless" ( alpha, delta_interval, last_value : f32 ) -> f32
|
||||
{
|
||||
result := (delta_interval * alpha) + (delta_interval * (1.0 - alpha))
|
||||
return result
|
||||
}
|
||||
|
||||
mov_avg_exp_f64 := #force_inline proc "contextless" ( alpha, delta_interval, last_value : f64 ) -> f64
|
||||
{
|
||||
result := (delta_interval * alpha) + (delta_interval * (1.0 - alpha))
|
||||
return result
|
||||
}
|
||||
|
||||
import "core:math/linalg"
|
||||
|
||||
Vec2 :: linalg.Vector2f32
|
||||
|
17
code/render.odin
Normal file
17
code/render.odin
Normal file
@ -0,0 +1,17 @@
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -32,53 +32,53 @@ when ODIN_OS == OS_Type.Windows {
|
||||
// return points *
|
||||
// }
|
||||
|
||||
f32_cm_to_pixels :: proc(cm: f32) -> f32 {
|
||||
f32_cm_to_pixels :: #force_inline proc "contextless"(cm: f32) -> f32 {
|
||||
screen_ppcm := get_state().app_window.ppcm
|
||||
return cm * screen_ppcm
|
||||
}
|
||||
|
||||
f32_pixels_to_cm :: proc(pixels: f32) -> f32 {
|
||||
f32_pixels_to_cm :: #force_inline proc "contextless"(pixels: f32) -> f32 {
|
||||
screen_ppcm := get_state().app_window.ppcm
|
||||
cm_per_pixel := 1.0 / screen_ppcm
|
||||
return pixels * cm_per_pixel
|
||||
}
|
||||
|
||||
f32_points_to_pixels :: proc(points: f32) -> f32 {
|
||||
f32_points_to_pixels :: #force_inline proc "contextless"(points: f32) -> f32 {
|
||||
screen_ppcm := get_state().app_window.ppcm
|
||||
cm_per_pixel := 1.0 / screen_ppcm
|
||||
return points * DPT_PPCM * cm_per_pixel
|
||||
}
|
||||
|
||||
f32_pixels_to_points :: proc(pixels: f32) -> f32 {
|
||||
f32_pixels_to_points :: #force_inline proc "contextless"(pixels: f32) -> f32 {
|
||||
screen_ppcm := get_state().app_window.ppcm
|
||||
cm_per_pixel := 1.0 / screen_ppcm
|
||||
return pixels * cm_per_pixel * Points_Per_CM
|
||||
}
|
||||
|
||||
vec2_cm_to_pixels :: proc(v: Vec2) -> Vec2 {
|
||||
vec2_cm_to_pixels :: #force_inline proc "contextless"(v: Vec2) -> Vec2 {
|
||||
screen_ppcm := get_state().app_window.ppcm
|
||||
return v * screen_ppcm
|
||||
}
|
||||
|
||||
vec2_pixels_to_cm :: proc(v: Vec2) -> Vec2 {
|
||||
vec2_pixels_to_cm :: #force_inline proc "contextless"(v: Vec2) -> Vec2 {
|
||||
screen_ppcm := get_state().app_window.ppcm
|
||||
cm_per_pixel := 1.0 / screen_ppcm
|
||||
return v * cm_per_pixel
|
||||
}
|
||||
|
||||
vec2_points_to_pixels :: proc(vpoints: Vec2) -> Vec2 {
|
||||
vec2_points_to_pixels :: #force_inline proc "contextless"(vpoints: Vec2) -> Vec2 {
|
||||
screen_ppcm := get_state().app_window.ppcm
|
||||
cm_per_pixel := 1.0 / screen_ppcm
|
||||
return vpoints * DPT_PPCM * cm_per_pixel
|
||||
}
|
||||
|
||||
range2_cm_to_pixels :: proc( range : Range2 ) -> Range2 {
|
||||
range2_cm_to_pixels :: #force_inline proc "contextless"( range : Range2 ) -> Range2 {
|
||||
screen_ppcm := get_state().app_window.ppcm
|
||||
result := Range2 { pts = { range.min * screen_ppcm, range.max * screen_ppcm }}
|
||||
return result
|
||||
}
|
||||
|
||||
range2_pixels_to_cm :: proc( range : Range2 ) -> Range2 {
|
||||
range2_pixels_to_cm :: #force_inline proc "contextless"( range : Range2 ) -> Range2 {
|
||||
screen_ppcm := get_state().app_window.ppcm
|
||||
cm_per_pixel := 1.0 / screen_ppcm
|
||||
result := Range2 { pts = { range.min * cm_per_pixel, range.max * cm_per_pixel }}
|
||||
@ -132,7 +132,7 @@ screen_size :: proc "contextless" () -> AreaSize {
|
||||
return transmute(AreaSize) ( extent * 2.0 )
|
||||
}
|
||||
|
||||
screen_get_corners :: proc() -> BoundsCorners2 {
|
||||
screen_get_corners :: #force_inline proc "contextless"() -> BoundsCorners2 {
|
||||
state := get_state(); using state
|
||||
screen_extent := state.app_window.extent
|
||||
top_left := Vec2 { -screen_extent.x, screen_extent.y }
|
||||
@ -142,16 +142,17 @@ screen_get_corners :: proc() -> BoundsCorners2 {
|
||||
return { top_left, top_right, bottom_left, bottom_right }
|
||||
}
|
||||
|
||||
view_get_bounds :: proc() -> Range2 {
|
||||
state := get_state(); using state
|
||||
cam := & project.workspace.cam
|
||||
screen_extent := state.app_window.extent
|
||||
top_left := Vec2 { cam.target.x, -cam.target.y } + Vec2 { -screen_extent.x, screen_extent.y} * (1/cam.zoom)
|
||||
bottom_right := Vec2 { cam.target.x, -cam.target.y } + Vec2 { screen_extent.x, -screen_extent.y} * (1/cam.zoom)
|
||||
return range2(top_left, bottom_right)
|
||||
view_get_bounds :: #force_inline proc "contextless"() -> Range2 {
|
||||
state := get_state(); using state
|
||||
cam := & project.workspace.cam
|
||||
screen_extent := state.app_window.extent
|
||||
cam_zoom_ratio := 1.0 / cam.zoom
|
||||
bottom_left := Vec2 { cam.target.x, -cam.target.y } + Vec2 { -screen_extent.x, -screen_extent.y} * cam_zoom_ratio
|
||||
top_right := Vec2 { cam.target.x, -cam.target.y } + Vec2 { screen_extent.x, screen_extent.y} * cam_zoom_ratio
|
||||
return range2( bottom_left, top_right )
|
||||
}
|
||||
|
||||
view_get_corners :: proc() -> BoundsCorners2 {
|
||||
view_get_corners :: #force_inline proc "contextless"() -> BoundsCorners2 {
|
||||
state := get_state(); using state
|
||||
cam := & project.workspace.cam
|
||||
cam_zoom_ratio := 1.0 / cam.zoom
|
||||
@ -170,22 +171,22 @@ screen_to_world :: #force_inline proc "contextless" (pos: Vec2) -> Vec2 {
|
||||
return result
|
||||
}
|
||||
|
||||
screen_to_render :: proc(pos: Vec2) -> Vec2 {
|
||||
screen_to_render :: #force_inline proc "contextless"(pos: Vec2) -> Vec2 {
|
||||
screen_extent := transmute(Vec2) get_state().project.workspace.cam.offset
|
||||
return pos + { screen_extent.x, -screen_extent.y }
|
||||
}
|
||||
|
||||
world_screen_extent :: proc() -> Extents2 {
|
||||
world_screen_extent :: #force_inline proc "contextless"() -> Extents2 {
|
||||
state := get_state(); using state
|
||||
cam_zoom_ratio := 1.0 / project.workspace.cam.zoom
|
||||
return app_window.extent * cam_zoom_ratio
|
||||
}
|
||||
|
||||
world_to_screen_pos :: proc(position: Vec2) -> Vec2 {
|
||||
world_to_screen_pos :: #force_inline proc "contextless"(position: Vec2) -> Vec2 {
|
||||
return { position.x, position.y * -1 }
|
||||
}
|
||||
|
||||
world_to_screen_no_zoom :: proc(position: Vec2) -> Vec2 {
|
||||
world_to_screen_no_zoom :: #force_inline proc "contextless"(position: Vec2) -> Vec2 {
|
||||
state := get_state(); using state
|
||||
cam_zoom_ratio := 1.0 / state.project.workspace.cam.zoom
|
||||
return { position.x, position.y * -1 } * cam_zoom_ratio
|
||||
|
@ -4,6 +4,7 @@ import "core:fmt"
|
||||
|
||||
import rl "vendor:raylib"
|
||||
|
||||
//@(optimization_mode="speed")
|
||||
render :: proc()
|
||||
{
|
||||
profile(#procedure)
|
||||
@ -23,7 +24,7 @@ render :: proc()
|
||||
//region Render Screenspace
|
||||
{
|
||||
profile("Render Screenspace")
|
||||
fps_msg := str_fmt_tmp( "FPS: %f", 1 / (frametime_elapsed_ms * MS_To_S) )
|
||||
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_pos := screen_get_corners().top_right - { fps_msg_width, 0 }
|
||||
debug_draw_text( fps_msg, fps_msg_pos, 16.0, color = rl.GREEN )
|
||||
@ -77,21 +78,21 @@ render :: proc()
|
||||
|
||||
ui := project.workspace.ui
|
||||
|
||||
debug_text("Box Count: %v", ui.built_box_count )
|
||||
// debug_text("Box Count: %v", ui.built_box_count )
|
||||
|
||||
hot_box := ui_box_from_key( ui.curr_cache, ui.hot )
|
||||
active_box := ui_box_from_key( ui.curr_cache, ui.active )
|
||||
if hot_box != nil {
|
||||
debug_text("Hot Box : %v", hot_box.label.str )
|
||||
debug_text("Hot Range2: %v", hot_box.computed.bounds.pts)
|
||||
// debug_text("Hot Range2: %v", hot_box.computed.bounds.pts)
|
||||
}
|
||||
if active_box != nil{
|
||||
debug_text("Active Box: %v", active_box.label.str )
|
||||
// debug_text("Active Box: %v", active_box.label.str )
|
||||
}
|
||||
// debug_text("Active Resizing: %v", ui.active_start_signal.resizing)
|
||||
|
||||
view := view_get_bounds()
|
||||
debug_text("View Bounds (World): %v", view.pts )
|
||||
// debug_text("View Bounds (World): %v", view.pts )
|
||||
|
||||
debug.draw_debug_text_y = 50
|
||||
}
|
||||
@ -122,9 +123,9 @@ render_mode_2d :: proc()
|
||||
}}
|
||||
view_rect := rl.Rectangle {
|
||||
render_view.min.x,
|
||||
render_view.min.y,
|
||||
render_view.max.x - render_view.min.x,
|
||||
render_view.max.y - render_view.min.y,
|
||||
render_view.max.y,
|
||||
abs(render_view.max.x - render_view.min.x),
|
||||
abs(render_view.max.y - render_view.min.y),
|
||||
}
|
||||
rl.DrawRectangleRounded( view_rect, 0.3, 9, { 255, 0, 0, 20 } )
|
||||
}
|
||||
@ -141,7 +142,7 @@ render_mode_2d :: proc()
|
||||
current := root.first
|
||||
for ; current != nil; current = ui_box_tranverse_next( current )
|
||||
{
|
||||
profile("Box")
|
||||
// profile("Box")
|
||||
parent := current.parent
|
||||
|
||||
style := current.style
|
||||
@ -149,18 +150,25 @@ render_mode_2d :: proc()
|
||||
|
||||
computed_size := computed.bounds.p1 - computed.bounds.p0
|
||||
|
||||
if ! within_range2( view_bounds, computed.bounds ) {
|
||||
if ! intersects_range2( view_bounds, computed.bounds ) {
|
||||
continue
|
||||
}
|
||||
|
||||
// TODO(Ed) : Render Borders
|
||||
|
||||
// profile_begin("Calculating Raylib rectangles")
|
||||
render_anchors := range2(
|
||||
world_to_screen_pos(computed.anchors.min),
|
||||
world_to_screen_pos(computed.anchors.max),
|
||||
)
|
||||
render_margins := range2(
|
||||
world_to_screen_pos(computed.margins.min),
|
||||
world_to_screen_pos(computed.margins.max),
|
||||
)
|
||||
render_bounds := range2(
|
||||
world_to_screen_pos(computed.bounds.min),
|
||||
world_to_screen_pos(computed.bounds.max),
|
||||
)
|
||||
|
||||
render_padding := range2(
|
||||
world_to_screen_pos(computed.padding.min),
|
||||
world_to_screen_pos(computed.padding.max),
|
||||
@ -170,24 +178,11 @@ render_mode_2d :: proc()
|
||||
world_to_screen_pos(computed.content.max),
|
||||
)
|
||||
|
||||
rect_bounds := rl.Rectangle {
|
||||
render_bounds.min.x,
|
||||
render_bounds.max.y,
|
||||
abs(render_bounds.max.x - render_bounds.min.x),
|
||||
abs(render_bounds.max.y - render_bounds.min.y),
|
||||
}
|
||||
rect_padding := rl.Rectangle {
|
||||
render_padding.min.x,
|
||||
render_padding.max.y,
|
||||
abs(render_padding.max.x - render_padding.min.x),
|
||||
abs(render_padding.max.y - render_padding.min.y),
|
||||
}
|
||||
rect_content := rl.Rectangle {
|
||||
render_content.min.x,
|
||||
render_content.max.y,
|
||||
abs(render_content.max.x - render_content.min.x),
|
||||
abs(render_content.max.y - render_content.min.y),
|
||||
}
|
||||
rect_anchors := range2_to_rl_rect( render_anchors )
|
||||
rect_margins := range2_to_rl_rect( render_margins )
|
||||
rect_bounds := range2_to_rl_rect( render_bounds )
|
||||
rect_padding := range2_to_rl_rect( render_padding )
|
||||
rect_content := range2_to_rl_rect( render_content )
|
||||
// profile_end()
|
||||
|
||||
draw_rectangle :: #force_inline proc "contextless" ( rect : rl.Rectangle, style : UI_Style ) {
|
||||
|
@ -4,6 +4,7 @@ import "base:runtime"
|
||||
import "core:math"
|
||||
import "core:math/linalg"
|
||||
import "core:os"
|
||||
import str "core:strings"
|
||||
|
||||
import rl "vendor:raylib"
|
||||
|
||||
@ -63,6 +64,7 @@ frametime_delta32 :: #force_inline proc "contextless" () -> f32 {
|
||||
return cast(f32) get_state().frametime_delta_seconds
|
||||
}
|
||||
|
||||
//@(optimization_mode="speed")
|
||||
update :: proc( delta_time : f64 ) -> b32
|
||||
{
|
||||
profile(#procedure)
|
||||
@ -205,7 +207,7 @@ update :: proc( delta_time : f64 ) -> b32
|
||||
}
|
||||
default_layout := UI_Layout {
|
||||
anchor = {},
|
||||
alignment = { 0.0, 0.0 },
|
||||
alignment = { 0., 0.0 },
|
||||
text_alignment = { 0.0, 0.0 },
|
||||
// corner_radii = { 0.2, 0.2, 0.2, 0.2 },
|
||||
pos = { 0, 0 },
|
||||
@ -240,7 +242,7 @@ update :: proc( delta_time : f64 ) -> b32
|
||||
// test_text_box()
|
||||
|
||||
// test_parenting()
|
||||
if true
|
||||
if false
|
||||
{
|
||||
// frame := ui_widget( "Frame", {} )
|
||||
// ui_parent(frame)
|
||||
@ -292,11 +294,11 @@ update :: proc( delta_time : f64 ) -> b32
|
||||
}
|
||||
|
||||
child_layout := default_layout
|
||||
child_layout.size = range2({ 75, 75 }, { 0, 0 })
|
||||
child_layout.alignment = { 0.5, 0.0 }
|
||||
child_layout.size = range2({ 0, 0 }, { 0, 0 })
|
||||
child_layout.alignment = { 0.5, 0.5 }
|
||||
child_layout.margins = { 20, 20, 20, 20 }
|
||||
child_layout.padding = {}
|
||||
child_layout.anchor = range2({ 0.0, 0.0 }, { 0.0, 1.0 })
|
||||
child_layout.anchor = range2({ 0.0, 0.0 }, { 0.0, 0.0 })
|
||||
child_layout.pos = { 0, 0 }
|
||||
|
||||
child_theme := frame_style_default
|
||||
@ -310,16 +312,19 @@ update :: proc( delta_time : f64 ) -> b32
|
||||
}
|
||||
|
||||
// Whitespace AST test
|
||||
if false
|
||||
if true
|
||||
{
|
||||
profile("Whitespace AST test")
|
||||
|
||||
text_style := frame_style_default
|
||||
text_style.flags = {
|
||||
.Size_To_Text,
|
||||
.Origin_At_Anchor_Center,
|
||||
.Fixed_Position_X, .Fixed_Position_Y,
|
||||
// .Fixed_Width, .Fixed_Height,
|
||||
}
|
||||
text_style.text_alignment = { 0.0, 0.5 }
|
||||
text_style.alignment = { 0.0, 1.0 }
|
||||
text_style.size.min = { 1600, 30 }
|
||||
|
||||
text_theme := UI_StyleTheme { styles = {
|
||||
text_style,
|
||||
@ -332,7 +337,7 @@ update :: proc( delta_time : f64 ) -> b32
|
||||
text_theme.hot.bg_color = Color_Frame_Hover
|
||||
text_theme.active.bg_color = Color_Frame_Select
|
||||
|
||||
layout_text := default_layout
|
||||
layout_text := text_style.layout
|
||||
|
||||
ui_style_theme( text_theme )
|
||||
|
||||
@ -347,65 +352,114 @@ update :: proc( delta_time : f64 ) -> b32
|
||||
|
||||
// index := 0
|
||||
widgets : Array(UI_Widget)
|
||||
widgets, alloc_error = array_init( UI_Widget, frame_slab_allocator() )
|
||||
widgets, alloc_error = array_init_reserve( UI_Widget, frame_slab_allocator(), Kilobyte * 4 )
|
||||
widgets_ptr := & widgets
|
||||
|
||||
label_id := 0
|
||||
|
||||
line_id := 0
|
||||
for line in array_to_slice_num( debug.lorem_parse.lines )
|
||||
{
|
||||
profile("WS AST Line")
|
||||
|
||||
head := line.first
|
||||
for ; head != nil;
|
||||
{
|
||||
ui_style_theme_set_layout( layout_text )
|
||||
widget : UI_Widget
|
||||
|
||||
// We're assumping PWS_Token for now...
|
||||
// Eventually I'm going to flatten this, its not worth doing it the way I am...
|
||||
#partial switch head.type
|
||||
{
|
||||
case .Visible:
|
||||
label := str_intern( str_fmt_alloc( "%v %v", head.content.str, label_id ))
|
||||
widget = ui_text( label.str, head.content )
|
||||
label_id += 1
|
||||
|
||||
layout_text.pos.x += size_range2( widget.computed.bounds ).x
|
||||
|
||||
case .Spaces:
|
||||
label := str_intern( str_fmt_alloc( "%v %v", "space", label_id ))
|
||||
widget = ui_space( label.str )
|
||||
label_id += 1
|
||||
|
||||
for idx in 1 ..< len( head.content.runes )
|
||||
{
|
||||
// TODO(Ed): VIRTUAL WHITESPACE
|
||||
// widget.style.layout.size.x += range2_size( widget.computed.bounds )
|
||||
}
|
||||
layout_text.pos.x += size_range2( widget.computed.bounds ).x
|
||||
|
||||
case .Tabs:
|
||||
label := str_intern( str_fmt_alloc( "%v %v", "tab", label_id ))
|
||||
widget = ui_tab( label.str )
|
||||
label_id += 1
|
||||
|
||||
for idx in 1 ..< len( head.content.runes )
|
||||
{
|
||||
// widget.style.layout.size.x += range2_size( widget.computed.bounds )
|
||||
}
|
||||
layout_text.pos.x += size_range2( widget.computed.bounds ).x
|
||||
}
|
||||
|
||||
array_append( widgets_ptr, widget )
|
||||
head = head.next
|
||||
if line_id == 0 {
|
||||
line_id += 1
|
||||
continue
|
||||
}
|
||||
|
||||
layout_text.pos.x = default_layout.pos.x
|
||||
layout_text.pos.y -= 30
|
||||
ui_style_theme_set_layout( layout_text )
|
||||
line_hbox := ui_widget(str_fmt_alloc( "line %v", line_id ), {})
|
||||
|
||||
if line_hbox.key == ui.hot
|
||||
{
|
||||
line_hbox.text = StringCached {}
|
||||
ui_parent(line_hbox)
|
||||
|
||||
chunk_layout := layout_text
|
||||
chunk_layout.alignment = { 0.0, 1.0 }
|
||||
chunk_layout.anchor = range2({ 0.0, 0 }, { 0.0, 0 })
|
||||
chunk_layout.pos = {}
|
||||
|
||||
chunk_style := text_style
|
||||
chunk_style.flags = { .Fixed_Position_X, .Size_To_Text }
|
||||
chunk_style.layout = chunk_layout
|
||||
|
||||
chunk_theme := UI_StyleTheme { styles = {
|
||||
chunk_style,
|
||||
chunk_style,
|
||||
chunk_style,
|
||||
chunk_style,
|
||||
}}
|
||||
ui_style_theme( chunk_theme )
|
||||
|
||||
head := line.first
|
||||
for ; head != nil;
|
||||
{
|
||||
ui_style_theme_set_layout( chunk_layout )
|
||||
widget : UI_Widget
|
||||
|
||||
#partial switch head.type
|
||||
{
|
||||
case .Visible:
|
||||
label := str_intern( str_fmt_alloc( "%v %v", head.content.str, label_id ))
|
||||
widget = ui_text( label.str, head.content )
|
||||
label_id += 1
|
||||
|
||||
chunk_layout.pos.x += size_range2( widget.computed.bounds ).x
|
||||
|
||||
case .Spaces:
|
||||
label := str_intern( str_fmt_alloc( "%v %v", "space", label_id ))
|
||||
widget = ui_text_spaces( label.str )
|
||||
label_id += 1
|
||||
|
||||
for idx in 1 ..< len( head.content.runes )
|
||||
{
|
||||
// TODO(Ed): VIRTUAL WHITESPACE
|
||||
// widget.style.layout.size.x += range2_size( widget.computed.bounds )
|
||||
}
|
||||
chunk_layout.pos.x += size_range2( widget.computed.bounds ).x
|
||||
|
||||
case .Tabs:
|
||||
label := str_intern( str_fmt_alloc( "%v %v", "tab", label_id ))
|
||||
widget = ui_text_tabs( label.str )
|
||||
label_id += 1
|
||||
|
||||
for idx in 1 ..< len( head.content.runes )
|
||||
{
|
||||
// widget.style.layout.size.x += range2_size( widget.computed.bounds )
|
||||
}
|
||||
chunk_layout.pos.x += size_range2( widget.computed.bounds ).x
|
||||
}
|
||||
|
||||
array_append( widgets_ptr, widget )
|
||||
head = head.next
|
||||
}
|
||||
|
||||
line_hbox.style.size.min.x = chunk_layout.pos.x
|
||||
}
|
||||
else
|
||||
{
|
||||
builder_backing : [16 * Kilobyte] byte
|
||||
builder := str.builder_from_bytes( builder_backing[:] )
|
||||
|
||||
line_hbox.style.flags |= { .Size_To_Text }
|
||||
|
||||
head := line.first.next
|
||||
for ; head != nil;
|
||||
{
|
||||
str.write_string( & builder, head.content.str )
|
||||
head = head.next
|
||||
}
|
||||
|
||||
line_hbox.text = str_intern( to_string( builder ) )
|
||||
}
|
||||
|
||||
array_append( widgets_ptr, line_hbox )
|
||||
|
||||
layout_text.pos.x = text_style.layout.pos.x
|
||||
layout_text.pos.y += size_range2(line_hbox.computed.bounds).y
|
||||
line_id += 1
|
||||
}
|
||||
|
||||
label_id += 1
|
||||
label_id += 1 // Dummy action
|
||||
}
|
||||
}
|
||||
//endregion Imgui Tick
|
||||
|
16
code/ui.odin
16
code/ui.odin
@ -183,6 +183,10 @@ UI_StyleFlag :: enum u32 {
|
||||
Fixed_Width,
|
||||
Fixed_Height,
|
||||
|
||||
// Sets the (0, 0) position of the child box to the parents anchor's center (post-margins bounds)
|
||||
// By Default, the origin is at the top left of the anchor's bounds
|
||||
Origin_At_Anchor_Center,
|
||||
|
||||
// Will size the box to its text. (Padding & Margins will thicken )
|
||||
Size_To_Text,
|
||||
Text_Wrap,
|
||||
@ -340,7 +344,7 @@ ui_reload :: proc( ui : ^ UI_State, cache_allocator : Allocator )
|
||||
ui_shutdown :: proc() {
|
||||
}
|
||||
|
||||
ui_box_equal :: proc( a, b : ^ UI_Box ) -> b32 {
|
||||
ui_box_equal :: #force_inline proc "contextless" ( a, b : ^ UI_Box ) -> b32 {
|
||||
BoxSize :: size_of(UI_Box)
|
||||
|
||||
result : b32 = true
|
||||
@ -349,10 +353,11 @@ ui_box_equal :: proc( a, b : ^ UI_Box ) -> b32 {
|
||||
return result
|
||||
}
|
||||
|
||||
ui_box_from_key :: proc( cache : ^HMapZPL(UI_Box), key : UI_Key ) -> (^UI_Box) {
|
||||
ui_box_from_key :: #force_inline proc ( cache : ^HMapZPL(UI_Box), key : UI_Key ) -> (^UI_Box) {
|
||||
return zpl_hmap_get( cache, cast(u64) key )
|
||||
}
|
||||
|
||||
//@(optimization_mode="speed")
|
||||
ui_box_make :: proc( flags : UI_BoxFlags, label : string ) -> (^ UI_Box)
|
||||
{
|
||||
// profile(#procedure)
|
||||
@ -407,8 +412,10 @@ 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
|
||||
if box.first != nil {
|
||||
if intersects_range2( view_get_bounds(), box.computed.bounds) && box.first != nil
|
||||
{
|
||||
return box.first
|
||||
}
|
||||
|
||||
@ -479,7 +486,8 @@ ui_graph_build :: proc( ui : ^ UI_State ) {
|
||||
ui_graph_build_begin( ui )
|
||||
}
|
||||
|
||||
ui_key_from_string :: proc( value : string ) -> UI_Key
|
||||
//@(optimization_mode="speed")
|
||||
ui_key_from_string :: #force_inline proc "contextless" ( value : string ) -> UI_Key
|
||||
{
|
||||
// profile(#procedure)
|
||||
USE_RAD_DEBUGGERS_METHOD :: true
|
||||
|
@ -3,6 +3,8 @@ package sectr
|
||||
import "core:math"
|
||||
import "core:math/linalg"
|
||||
|
||||
// Note(Ed): This is naturally pretty expensive
|
||||
//@(optimization_mode="speed")
|
||||
ui_compute_layout :: proc()
|
||||
{
|
||||
profile(#procedure)
|
||||
@ -21,7 +23,7 @@ ui_compute_layout :: proc()
|
||||
current := root.first
|
||||
for ; current != nil;
|
||||
{
|
||||
profile("Layout Box")
|
||||
// profile("Layout Box")
|
||||
style := current.style
|
||||
|
||||
// These are used to choose via multiplication weather to apply
|
||||
@ -118,15 +120,18 @@ ui_compute_layout :: proc()
|
||||
|
||||
// 5. Determine relative position
|
||||
|
||||
// TODO(Ed): Let the user determine the coordinate space origin?
|
||||
// rel_pos := margined_bounds_origin + alignment_offset + layout.pos
|
||||
rel_pos := margined_bounds_origin + layout.pos
|
||||
origin_center := margined_bounds_origin
|
||||
origin_top_left := Vec2 { margined_bounds.min.x, margined_bounds.max.y }
|
||||
|
||||
origin := .Origin_At_Anchor_Center in style.flags ? origin_center : origin_top_left
|
||||
|
||||
rel_pos := origin + layout.pos
|
||||
|
||||
if .Fixed_Position_X in style.flags {
|
||||
rel_pos.x = parent_center.x + layout.pos.x
|
||||
rel_pos.x = origin.x + layout.pos.x
|
||||
}
|
||||
if .Fixed_Position_Y in style.flags {
|
||||
rel_pos.y = parent_center.y + layout.pos.y
|
||||
rel_pos.y = origin.y + layout.pos.y
|
||||
}
|
||||
|
||||
vec2_one := Vec2 { 1, 1 }
|
||||
|
@ -1,5 +1,6 @@
|
||||
package sectr
|
||||
|
||||
//@(optimization_mode="speed")
|
||||
ui_signal_from_box :: proc ( box : ^ UI_Box ) -> UI_Signal
|
||||
{
|
||||
// profile(#procedure)
|
||||
@ -182,7 +183,6 @@ ui_signal_from_box :: proc ( box : ^ UI_Box ) -> UI_Signal
|
||||
if ! was_active {
|
||||
box.prev_style = box.style
|
||||
box.style_delta = 0
|
||||
log( str_fmt_tmp("NEW ACTIVE: %v", box.label.str))
|
||||
}
|
||||
box.style = stack_peek( & ui.theme_stack ).active
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ UI_Widget :: struct {
|
||||
using signal : UI_Signal,
|
||||
}
|
||||
|
||||
//@(optimization_mode="speed")
|
||||
ui_widget :: proc( label : string, flags : UI_BoxFlags ) -> (widget : UI_Widget)
|
||||
{
|
||||
// profile(#procedure)
|
||||
@ -14,6 +15,7 @@ ui_widget :: proc( label : string, flags : UI_BoxFlags ) -> (widget : UI_Widget)
|
||||
return
|
||||
}
|
||||
|
||||
//@(optimization_mode="speed")
|
||||
ui_button :: proc( label : string, flags : UI_BoxFlags = {} ) -> (btn : UI_Widget)
|
||||
{
|
||||
// profile(#procedure)
|
||||
@ -24,6 +26,7 @@ ui_button :: proc( label : string, flags : UI_BoxFlags = {} ) -> (btn : UI_Widge
|
||||
return
|
||||
}
|
||||
|
||||
//@(optimization_mode="speed")
|
||||
ui_text :: proc( label : string, content : StringCached, flags : UI_BoxFlags = {} ) -> UI_Widget
|
||||
{
|
||||
// profile(#procedure)
|
||||
@ -36,7 +39,8 @@ ui_text :: proc( label : string, content : StringCached, flags : UI_BoxFlags = {
|
||||
return { box, signal }
|
||||
}
|
||||
|
||||
ui_space :: proc( label : string, flags : UI_BoxFlags = {} ) -> UI_Widget
|
||||
//@(optimization_mode="speed")
|
||||
ui_text_spaces :: proc( label : string, flags : UI_BoxFlags = {} ) -> UI_Widget
|
||||
{
|
||||
// profile(#procedure)
|
||||
state := get_state(); using state
|
||||
@ -51,7 +55,8 @@ ui_space :: proc( label : string, flags : UI_BoxFlags = {} ) -> UI_Widget
|
||||
return { box, signal }
|
||||
}
|
||||
|
||||
ui_tab :: proc( label : string, flags : UI_BoxFlags = {} ) -> UI_Widget
|
||||
//@(optimization_mode="speed")
|
||||
ui_text_tabs :: proc( label : string, flags : UI_BoxFlags = {} ) -> UI_Widget
|
||||
{
|
||||
// profile(#procedure)
|
||||
state := get_state(); using state
|
||||
|
Reference in New Issue
Block a user