saving a mess of stuff with auto-layout before updating with new mess
This commit is contained in:
parent
159aedb592
commit
0627794e28
@ -15,8 +15,8 @@ Color_BG_TextBox_Green :: Color { 102, 102, 110, 255 }
|
||||
Color_Frame_Disabled :: Color { 22, 22, 22, 120 }
|
||||
Color_Frame_Hover :: Color { 122, 122, 125, 200 }
|
||||
Color_Frame_Select :: Color { 188, 188, 188, 220 }
|
||||
Color_GreyRed :: Color { 220, 100, 100, 125 }
|
||||
Color_White_A125 :: Color { 255, 255, 255, 125 }
|
||||
Color_GreyRed :: Color { 220, 100, 100, 165 }
|
||||
Color_White_A125 :: Color { 255, 255, 255, 165 }
|
||||
|
||||
Color_Debug_UI_Padding_Bounds :: Color { 40, 195, 170, 125 }
|
||||
Color_Debug_UI_Content_Bounds :: Color { 195, 40, 170, 125 }
|
||||
Color_Debug_UI_Padding_Bounds :: Color { 40, 195, 170, 160 }
|
||||
Color_Debug_UI_Content_Bounds :: Color { 170, 120, 240, 160 }
|
||||
|
@ -250,6 +250,13 @@ DebugData :: struct {
|
||||
mouse_vis : b32,
|
||||
last_mouse_pos : Vec2,
|
||||
|
||||
// UI Vis
|
||||
draw_ui_box_bounds_points : bool,
|
||||
draw_ui_margin_bounds : bool,
|
||||
draw_ui_anchor_bounds : bool,
|
||||
draw_UI_padding_bounds : bool,
|
||||
draw_ui_content_bounds : bool,
|
||||
|
||||
// Test First
|
||||
frame_2_created : b32,
|
||||
|
||||
|
@ -147,6 +147,8 @@ render_mode_2d :: proc()
|
||||
style := current.style
|
||||
computed := & current.computed
|
||||
|
||||
computed_size := computed.bounds.p1 - computed.bounds.p0
|
||||
|
||||
if ! within_range2( view_bounds, computed.bounds ) {
|
||||
continue
|
||||
}
|
||||
@ -228,7 +230,7 @@ render_mode_2d :: proc()
|
||||
{
|
||||
// profile("Resize Bounds")
|
||||
resize_border_width := cast(f32) get_state().config.ui_resize_border_width
|
||||
resize_percent_width := style.size * (resize_border_width * 1.0/ 200.0)
|
||||
resize_percent_width := computed_size * (resize_border_width * 1.0/ 200.0)
|
||||
resize_border_non_range := add(current.computed.bounds, range2(
|
||||
{ resize_percent_width.x, -resize_percent_width.x },
|
||||
{ -resize_percent_width.x, resize_percent_width.x }))
|
||||
@ -249,8 +251,14 @@ render_mode_2d :: proc()
|
||||
point_radius := 3 * cam_zoom_ratio
|
||||
|
||||
// profile_begin("circles")
|
||||
// rl.DrawCircleV( render_bounds.p0, point_radius, Color_Red )
|
||||
// rl.DrawCircleV( render_bounds.p1, point_radius, Color_Blue )
|
||||
// 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 )
|
||||
// profile_end()
|
||||
|
||||
if len(current.text.str) > 0 {
|
||||
|
@ -207,9 +207,10 @@ update :: proc( delta_time : f64 ) -> b32
|
||||
anchor = {},
|
||||
alignment = { 0.0, 0.0 },
|
||||
text_alignment = { 0.0, 0.0 },
|
||||
corner_radii = { 0.2, 0.2, 0.2, 0.2 },
|
||||
// corner_radii = { 0.2, 0.2, 0.2, 0.2 },
|
||||
pos = { 0, 0 },
|
||||
size = { 200, 200 },
|
||||
size = range2( { 1000, 1000 }, {}),
|
||||
// padding = { 20, 20, 20, 20 }
|
||||
}
|
||||
|
||||
frame_style_default := UI_Style {
|
||||
@ -230,8 +231,8 @@ update :: proc( delta_time : f64 ) -> b32
|
||||
frame_style_default,
|
||||
}}
|
||||
frame_theme.disabled.bg_color = Color_Frame_Disabled
|
||||
frame_theme.hot.bg_color = Color_Frame_Hover
|
||||
frame_theme.active.bg_color = Color_Frame_Select
|
||||
// frame_theme.hot.bg_color = Color_Frame_Hover
|
||||
frame_theme.active.bg_color = Color_Frame_Select
|
||||
ui_style_theme( frame_theme )
|
||||
|
||||
config.ui_resize_border_width = 2.5
|
||||
@ -241,42 +242,72 @@ update :: proc( delta_time : f64 ) -> b32
|
||||
// test_parenting()
|
||||
if true
|
||||
{
|
||||
frame := ui_widget( "Frame", {} )
|
||||
ui_parent(frame)
|
||||
|
||||
parent_layout := default_layout
|
||||
parent_layout.size = { 300, 300 }
|
||||
parent_layout.size = range2( { 300, 300 }, {} )
|
||||
parent_layout.alignment = { 0.0, 0.0 }
|
||||
parent_layout.padding = {}
|
||||
parent_layout.pos = { 0, 0 }
|
||||
|
||||
parent_theme := frame_style_default
|
||||
parent_theme.layout = parent_layout
|
||||
parent_theme.flags = {
|
||||
.Fixed_Width, .Fixed_Height,
|
||||
}
|
||||
ui_theme_via_style(parent_theme)
|
||||
|
||||
ui_style_theme_set_layout( parent_layout )
|
||||
parent := ui_widget( "Parent", { .Mouse_Clickable })
|
||||
parent := ui_widget( "Parent", { .Mouse_Clickable, .Mouse_Resizable })
|
||||
ui_parent(parent)
|
||||
{
|
||||
if parent.first_frame {
|
||||
debug.draggable_box_pos = parent.style.layout.pos + { 0, -100 }
|
||||
debug.draggable_box_size = parent.style.layout.size
|
||||
debug.draggable_box_pos = parent.style.layout.pos + { 0, 0 }
|
||||
debug.draggable_box_size = parent.style.layout.size.min
|
||||
}
|
||||
|
||||
if parent.dragging {
|
||||
debug.draggable_box_pos += mouse_world_delta()
|
||||
}
|
||||
|
||||
if parent.resizing
|
||||
{
|
||||
og_layout := ui_context.active_start_style.layout
|
||||
|
||||
center := debug.draggable_box_pos
|
||||
original_distance := linalg.distance(ui.active_start_signal.cursor_pos, center)
|
||||
cursor_distance := linalg.distance(parent.cursor_pos, center)
|
||||
scale_factor := cursor_distance * (1 / original_distance)
|
||||
|
||||
debug.draggable_box_size = og_layout.size.min * scale_factor
|
||||
}
|
||||
if (ui.hot == parent.key) && (ui.hot_resizable || ui.active_start_signal.resizing) {
|
||||
parent.style.bg_color = Color_Blue
|
||||
}
|
||||
|
||||
parent.style.layout.pos = debug.draggable_box_pos
|
||||
parent.style.layout.size.min = debug.draggable_box_size
|
||||
}
|
||||
|
||||
child_layout := default_layout
|
||||
child_layout.size = { 100, 100 }
|
||||
child_layout.alignment = { 0.5, 0.5 }
|
||||
child_layout.margins = { 20, 20, 20, 20 }
|
||||
child_layout.anchor = range2( { 0.5, 0.5 }, { 0.5, 0.5 })
|
||||
child_layout.size = range2({ 50, 50 }, { 200, 200 })
|
||||
child_layout.alignment = { 0.0, 0.0 }
|
||||
child_layout.margins = { 00, 00, 00, 00 }
|
||||
child_layout.padding = {}
|
||||
child_layout.anchor = range2({ 0.0, 0.0 }, { 0.0, 0.0 })
|
||||
child_layout.pos = { 0, 0 }
|
||||
|
||||
child_theme := frame_style_default
|
||||
// child_theme.flags = {}
|
||||
child_theme.flags = {
|
||||
// .Fixed_Width, .Fixed_Height,
|
||||
}
|
||||
child_theme.layout = child_layout
|
||||
ui_theme_via_style(child_theme)
|
||||
child := ui_widget( "Child", { .Mouse_Clickable })
|
||||
}
|
||||
|
||||
// Whitespace AST test
|
||||
if true
|
||||
if false
|
||||
{
|
||||
profile("Whitespace AST test")
|
||||
|
||||
@ -292,10 +323,10 @@ update :: proc( delta_time : f64 ) -> b32
|
||||
text_style,
|
||||
text_style,
|
||||
}}
|
||||
text_theme.default.bg_color = Color_Transparent
|
||||
text_theme.default.bg_color = Color_Transparent
|
||||
text_theme.disabled.bg_color = Color_Frame_Disabled
|
||||
text_theme.hot.bg_color = Color_Frame_Hover
|
||||
text_theme.active.bg_color = Color_Frame_Select
|
||||
text_theme.hot.bg_color = Color_Frame_Hover
|
||||
text_theme.active.bg_color = Color_Frame_Select
|
||||
|
||||
layout_text := default_layout
|
||||
|
||||
|
29
code/ui.odin
29
code/ui.odin
@ -54,6 +54,7 @@ UI_AnchorPresets :: enum u32 {
|
||||
|
||||
UI_BoxFlag :: enum u64 {
|
||||
Disabled,
|
||||
|
||||
Focusable,
|
||||
Click_To_Focus,
|
||||
|
||||
@ -137,23 +138,20 @@ UI_Layout :: struct {
|
||||
margins : UI_LayoutSide,
|
||||
padding : UI_LayoutSide,
|
||||
|
||||
// TODO(Ed): We cannot support individual corners unless we add it to raylib (or finally change the rendering backend)
|
||||
corner_radii : [Corner.Count]f32,
|
||||
|
||||
// Position in relative coordinate space.
|
||||
// If the box's flags has Fixed_Position, then this will be its aboslute position in the relative coordinate space
|
||||
pos : Vec2,
|
||||
// TODO(Ed) : Should everything no matter what its parent is use a WS_Pos instead of a raw vector pos?
|
||||
|
||||
// TODO(Ed): Support a min/max range for the size of a box
|
||||
size : Vec2,
|
||||
// size : Range2
|
||||
size : Range2,
|
||||
|
||||
// TODO(Ed) : Should thsi just always be WS_Pos for workspace UI?
|
||||
// (We can union either varient and just know based on checking if its the screenspace UI)
|
||||
// If the box is a child of the root parent, its automatically in world space and thus will use the tile_pos.
|
||||
tile_pos : WS_Pos,
|
||||
|
||||
size_to_text : b8,
|
||||
// TODO(Ed) : Add support for size_to_content?
|
||||
// size_to_content : b8,
|
||||
// tile_pos : WS_Pos,
|
||||
}
|
||||
|
||||
UI_Signal :: struct {
|
||||
@ -175,11 +173,22 @@ UI_Signal :: struct {
|
||||
}
|
||||
|
||||
UI_StyleFlag :: enum u32 {
|
||||
|
||||
// Will perform scissor pass on children to their parent's bounds
|
||||
// (Specified in the parent)
|
||||
Clip_Children_To_Bounds,
|
||||
|
||||
// Enforces the widget will always remain in a specific position relative to the parent.
|
||||
// Overriding the anchors and margins.
|
||||
Fixed_Position_X,
|
||||
Fixed_Position_Y,
|
||||
|
||||
// Enroces the widget will maintain its size reguardless of any constraints
|
||||
// Will override parent constraints
|
||||
Fixed_Width,
|
||||
Fixed_Height,
|
||||
|
||||
Size_To_Text,
|
||||
Text_Wrap,
|
||||
|
||||
Count,
|
||||
@ -200,9 +209,11 @@ UI_Style :: struct {
|
||||
bg_color : Color,
|
||||
border_color : Color,
|
||||
|
||||
// TODO(Ed) : Add support for this eventually
|
||||
blur_size : f32,
|
||||
|
||||
font : FontID,
|
||||
// TODO(Ed): Should this get moved to the layout struct? Techncially font-size is mainly
|
||||
font_size : f32,
|
||||
text_color : Color,
|
||||
|
||||
@ -210,6 +221,8 @@ UI_Style :: struct {
|
||||
|
||||
using layout : UI_Layout,
|
||||
|
||||
// Used with style, prev_style, and style_delta to produce a simple interpolated animation
|
||||
// Applied in the layout pass & the rendering pass for their associated fields.
|
||||
transition_time : f32,
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,8 @@
|
||||
package sectr
|
||||
|
||||
import "core:math"
|
||||
import "core:math/linalg"
|
||||
|
||||
ui_compute_layout :: proc()
|
||||
{
|
||||
profile(#procedure)
|
||||
@ -13,7 +16,7 @@ ui_compute_layout :: proc()
|
||||
layout := & style.layout
|
||||
|
||||
bounds.min = layout.pos
|
||||
bounds.max = layout.size
|
||||
bounds.max = layout.size.min
|
||||
|
||||
computed.content = bounds^
|
||||
computed.padding = {}
|
||||
@ -30,85 +33,201 @@ ui_compute_layout :: proc()
|
||||
style := current.style
|
||||
layout := & style.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 style.flags)
|
||||
fixed_pos_y : f32 = cast(f32) int(.Fixed_Position_Y in style.flags)
|
||||
fixed_width : f32 = cast(f32) int(.Fixed_Width in style.flags)
|
||||
fixed_height : f32 = cast(f32) int(.Fixed_Height in style.flags)
|
||||
|
||||
size_to_text : bool = .Size_To_Text in style.flags
|
||||
|
||||
|
||||
margins := range2(
|
||||
{ layout.margins.left, -layout.margins.top },
|
||||
{ -layout.margins.right, layout.margins.bottom },
|
||||
)
|
||||
|
||||
margined_bounds := range2(
|
||||
parent_content.p0 + margins.p0,
|
||||
parent_content.p1 + margins.p1,
|
||||
)
|
||||
|
||||
margined_size := margined_bounds.p1 - margined_bounds.p0
|
||||
|
||||
anchored_bounds := range2(
|
||||
margined_bounds.p0 + margined_size * layout.anchor.p0,
|
||||
margined_bounds.p0 + margined_size * layout.anchor.p1,
|
||||
)
|
||||
|
||||
anchored_size := Vec2 {
|
||||
anchored_bounds.max.x - anchored_bounds.min.x,
|
||||
anchored_bounds.max.y - anchored_bounds.min.y,
|
||||
}
|
||||
margined_size := linalg.abs(margined_bounds.p1 - margined_bounds.p0)
|
||||
|
||||
anchor := & layout.anchor
|
||||
pos : Vec2
|
||||
if UI_StyleFlag.Fixed_Position_X in style.flags {
|
||||
pos.x = layout.pos.x
|
||||
pos.x += anchored_bounds.p0.x
|
||||
// Margins + Anchors Applied
|
||||
adjusted_bounds := range2(
|
||||
{ margined_bounds.p0.x + margined_size.x * anchor.p0.x, margined_bounds.p0.y + margined_size.y * anchor.p0.y },
|
||||
{ margined_bounds.p1.x + margined_size.x * anchor.p1.x, margined_bounds.p1.y + margined_size.y * anchor.p1.y },
|
||||
)
|
||||
adjusted_bounds_size := linalg.abs(adjusted_bounds.p1 - adjusted_bounds.p0)
|
||||
|
||||
// Resolves final constrained bounds of the parent for the child box
|
||||
// Will be applied to the box after the child's positon is resolved.
|
||||
|
||||
fixed_pos := Vec2 { fixed_pos_x, fixed_pos_y }
|
||||
constraint_min := adjusted_bounds.min //* (1 - fixed_pos) + parent_content.min * fixed_pos
|
||||
constraint_max := adjusted_bounds.max //* (1 - fixed_pos) + parent_content.max * fixed_pos
|
||||
|
||||
// constraint_min_x := adjusted_bounds.min.x //* (1 - fixed_pos_x) + parent_content.min.x * fixed_pos_x
|
||||
// constraint_min_y := adjusted_bounds.min.y //* (1 - fixed_pos_y) + parent_content.min.y * fixed_pos_y
|
||||
// constraint_max_x := adjusted_bounds.max.x //* (1 - fixed_pos_x) + parent_content.max.x * fixed_pos_x
|
||||
// constraint_max_y := adjusted_bounds.max.y //* (1 - fixed_pos_y) + parent_content.max.y * fixed_pos_y
|
||||
|
||||
constrained_bounds := range2(
|
||||
constraint_min,
|
||||
constraint_max,
|
||||
// { constraint_min_x, constraint_min_y },
|
||||
// { constraint_max_x, constraint_max_y },
|
||||
)
|
||||
constrained_size := linalg.abs(constrained_bounds.p1 - constrained_bounds.p0)
|
||||
|
||||
|
||||
/*
|
||||
If fixed position (X or Y):
|
||||
* Ignore Margins
|
||||
* Ignore Anchors
|
||||
|
||||
If fixed size (X or Y):
|
||||
* Ignore Parent constraints (can only be clipped)
|
||||
|
||||
If auto-sized:
|
||||
* Enforce parent size constraint of bounds relative to
|
||||
where the adjusted content bounds are after applying margins & anchors.
|
||||
The 'side' conflicting with the bounds will end at that bound side instead of clipping.
|
||||
|
||||
If size.min is not 0:
|
||||
* Ignore parent constraints if the bounds go below that value.
|
||||
|
||||
If size.max is not 0:
|
||||
* Allow the child box to spread to entire adjusted content bounds.
|
||||
*/
|
||||
|
||||
size_unit_bounds := range2(
|
||||
{ 0.0, 0.0 },
|
||||
{ 1.0, -1.0 },
|
||||
)
|
||||
|
||||
alignment := layout.alignment
|
||||
aligned_unit_bounds := range2(
|
||||
size_unit_bounds.p0 + { -alignment.x, alignment.y },
|
||||
size_unit_bounds.p1 - { alignment.x, -alignment.y },
|
||||
)
|
||||
|
||||
wtf := range2(
|
||||
{ constrained_bounds.p0.x, constrained_bounds.p0.y },
|
||||
{ constrained_bounds.p1.x, constrained_bounds.p1.y },
|
||||
)
|
||||
|
||||
// projected_bounds := range2(
|
||||
// aligned_unit_bounds.p0 * wtf.p0,
|
||||
// aligned_unit_bounds.p1 * wtf.p1,
|
||||
// )
|
||||
|
||||
|
||||
constrained_half_size := constrained_size * 0.5
|
||||
min_half_size := layout.size.min * 0.5
|
||||
max_half_size := layout.size.max * 0.5
|
||||
half_size := linalg.max( constrained_half_size, min_half_size )
|
||||
half_size = linalg.min( half_size, max_half_size )
|
||||
|
||||
projected_bounds := range2(
|
||||
aligned_unit_bounds.p0 * half_size,
|
||||
aligned_unit_bounds.p1 * half_size,
|
||||
)
|
||||
|
||||
rel_projected_bounds := range2(
|
||||
layout.pos + projected_bounds.p0,
|
||||
layout.pos + projected_bounds.p1,
|
||||
)
|
||||
|
||||
bounds : Range2
|
||||
|
||||
// Resolve and apply the size constraint based off of positon of box and the constrained bounds
|
||||
|
||||
// Check to see if left or right side is over
|
||||
if ! (.Fixed_Width in style.flags)
|
||||
{
|
||||
bounds.p0.x = rel_projected_bounds.p0.x < constrained_bounds.p0.x ? constrained_bounds.p0.x : rel_projected_bounds.p0.x
|
||||
bounds.p1.x = rel_projected_bounds.p1.x > constrained_bounds.p1.x ? constrained_bounds.p1.x : rel_projected_bounds.p1.x
|
||||
}
|
||||
if UI_StyleFlag.Fixed_Position_Y in style.flags {
|
||||
pos.y = layout.pos.y
|
||||
pos.y += anchored_bounds.p0.y
|
||||
else {
|
||||
size_unit_bounds := range2(
|
||||
{ 0.0, 0.0 },
|
||||
{ 1.0, -1.0 },
|
||||
)
|
||||
|
||||
alignment := layout.alignment
|
||||
aligned_unit_bounds := range2(
|
||||
size_unit_bounds.p0 + { -alignment.x, alignment.y },
|
||||
size_unit_bounds.p1 - { alignment.x, -alignment.y },
|
||||
)
|
||||
|
||||
// Apply size.p0.x directly
|
||||
bounds.p0.x = aligned_unit_bounds.p0.x * layout.size.min.x
|
||||
bounds.p1.x = aligned_unit_bounds.p1.x * layout.size.min.x
|
||||
|
||||
bounds.p0.x += constrained_bounds.p0.x
|
||||
bounds.p1.x += constrained_bounds.p0.x
|
||||
|
||||
bounds.p0.x += layout.pos.x
|
||||
bounds.p1.x += layout.pos.x
|
||||
}
|
||||
|
||||
if ! (.Fixed_Height in style.flags)
|
||||
{
|
||||
bounds.p0.y = rel_projected_bounds.p0.y > constrained_bounds.p0.y ? constrained_bounds.p0.y : rel_projected_bounds.p0.y
|
||||
bounds.p1.y = rel_projected_bounds.p1.y < constrained_bounds.p1.y ? constrained_bounds.p1.y : rel_projected_bounds.p1.y
|
||||
}
|
||||
else {
|
||||
size_unit_bounds := range2(
|
||||
{ 0.0, 0.0 },
|
||||
{ 1.0, -1.0 },
|
||||
)
|
||||
|
||||
alignment := layout.alignment
|
||||
aligned_unit_bounds := range2(
|
||||
size_unit_bounds.p0 + { -alignment.x, alignment.y },
|
||||
size_unit_bounds.p1 - { alignment.x, -alignment.y },
|
||||
)
|
||||
|
||||
// Apply size.p0.y directly
|
||||
bounds.p0.y = aligned_unit_bounds.p0.y * layout.size.min.y
|
||||
bounds.p1.y = aligned_unit_bounds.p1.y * layout.size.min.y
|
||||
|
||||
bounds.p0.y += constrained_bounds.p0.y //+ aligned_unit_bounds
|
||||
bounds.p1.y += constrained_bounds.p0.y //+ aligned_unit_bounds
|
||||
|
||||
bounds.p0.y += layout.pos.y
|
||||
bounds.p1.y += layout.pos.y
|
||||
}
|
||||
|
||||
// Enforce the min/max size
|
||||
bounds_size := bounds.p1 - bounds.p0
|
||||
// if bounds_size > layout.size.max {
|
||||
// Enforce max
|
||||
|
||||
|
||||
// }
|
||||
|
||||
|
||||
text_size : Vec2
|
||||
// If the computed matches, we alreayd have the size, don't bother.
|
||||
// if computed.text_size.y == style.font_size {
|
||||
if current.first_frame || ! style.size_to_text || computed.text_size.y != size_range2(computed.bounds).y {
|
||||
// If the computed matches, we already have the size, don't bother.
|
||||
if current.first_frame || ! size_to_text || computed.text_size.y != size_range2(computed.bounds).y {
|
||||
text_size = cast(Vec2) measure_text_size( current.text.str, style.font, style.font_size, 0 )
|
||||
}
|
||||
else {
|
||||
text_size = computed.text_size
|
||||
}
|
||||
|
||||
size : Vec2
|
||||
if UI_StyleFlag.Fixed_Width in style.flags {
|
||||
size.x = layout.size.x
|
||||
}
|
||||
else {
|
||||
size.x = anchored_size.x
|
||||
if size_to_text {
|
||||
// size = text_size
|
||||
}
|
||||
|
||||
if UI_StyleFlag.Fixed_Height in style.flags {
|
||||
size.y = layout.size.y
|
||||
}
|
||||
else {
|
||||
size.y = anchored_size.y
|
||||
}
|
||||
|
||||
if style.size_to_text {
|
||||
size = text_size
|
||||
}
|
||||
|
||||
half_size := size * 0.5
|
||||
size_bounds := range2(
|
||||
Vec2 {},
|
||||
{ size.x, -size.y },
|
||||
)
|
||||
|
||||
aligned_bounds := range2(
|
||||
size_bounds.p0 + size * { -layout.alignment.x, layout.alignment.y },
|
||||
size_bounds.p1 - size * { layout.alignment.x, -layout.alignment.y },
|
||||
)
|
||||
|
||||
bounds := & computed.bounds
|
||||
(bounds^) = aligned_bounds
|
||||
(bounds^) = range2(
|
||||
pos + aligned_bounds.p0,
|
||||
pos + aligned_bounds.p1,
|
||||
)
|
||||
computed.bounds = bounds
|
||||
|
||||
border_offset := Vec2 { layout.border_width, layout.border_width }
|
||||
padding := & computed.padding
|
||||
|
@ -15,8 +15,10 @@ ui_signal_from_box :: proc ( box : ^ UI_Box ) -> UI_Signal
|
||||
signal.cursor_pos = ui_cursor_pos()
|
||||
signal.cursor_over = cast(b8) pos_within_range2( signal.cursor_pos, box.computed.bounds )
|
||||
|
||||
computed_size := box.computed.bounds.p1 - box.computed.bounds.p0
|
||||
|
||||
resize_border_width := cast(f32) get_state().config.ui_resize_border_width
|
||||
resize_percent_width := box.style.size * (resize_border_width * 1.0/ 200.0)
|
||||
resize_percent_width := computed_size * (resize_border_width * 1.0/ 200.0)
|
||||
resize_border_non_range := add(box.computed.bounds, range2(
|
||||
{ resize_percent_width.x, -resize_percent_width.x },
|
||||
{ -resize_percent_width.x, resize_percent_width.x }))
|
||||
|
@ -31,14 +31,14 @@ test_draggable :: proc()
|
||||
// alignment = { 1.0, 1.0 },
|
||||
// corner_radii = { 0.3, 0.3, 0.3, 0.3 },
|
||||
pos = { 0, 0 },
|
||||
size = { 200, 200 },
|
||||
size = range2({ 200, 200 }, {}),
|
||||
}
|
||||
ui_style_theme_set_layout( draggable_layout )
|
||||
|
||||
draggable := ui_widget( "Draggable Box!", UI_BoxFlags { .Mouse_Clickable, .Mouse_Resizable } )
|
||||
if draggable.first_frame {
|
||||
debug.draggable_box_pos = draggable.style.layout.pos + { 0, -100 }
|
||||
debug.draggable_box_size = draggable.style.layout.size
|
||||
debug.draggable_box_size = draggable.style.layout.size.min
|
||||
}
|
||||
|
||||
// Dragging
|
||||
@ -56,7 +56,7 @@ test_draggable :: proc()
|
||||
cursor_distance := linalg.distance(draggable.cursor_pos, center)
|
||||
scale_factor := cursor_distance * (1 / original_distance)
|
||||
|
||||
debug.draggable_box_size = og_layout.size * scale_factor
|
||||
debug.draggable_box_size = og_layout.size.min * scale_factor
|
||||
}
|
||||
|
||||
if (ui.hot == draggable.key) && (ui.hot_resizable || ui.active_start_signal.resizing) {
|
||||
@ -64,7 +64,7 @@ test_draggable :: proc()
|
||||
}
|
||||
|
||||
draggable.style.layout.pos = debug.draggable_box_pos
|
||||
draggable.style.layout.size = debug.draggable_box_size
|
||||
draggable.style.layout.size.min = debug.draggable_box_size
|
||||
}
|
||||
|
||||
test_text_box :: proc()
|
||||
|
3
code/ui_util.odin
Normal file
3
code/ui_util.odin
Normal file
@ -0,0 +1,3 @@
|
||||
package sectr
|
||||
|
||||
|
@ -27,46 +27,41 @@ ui_button :: proc( label : string, flags : UI_BoxFlags = {} ) -> (btn : UI_Widge
|
||||
ui_text :: proc( label : string, content : StringCached, flags : UI_BoxFlags = {} ) -> UI_Widget
|
||||
{
|
||||
// profile(#procedure)
|
||||
|
||||
state := get_state(); using state
|
||||
|
||||
box := ui_box_make( flags, label )
|
||||
signal := ui_signal_from_box( box )
|
||||
|
||||
box.text = content
|
||||
box.style.layout.size_to_text = true
|
||||
return { box, signal }
|
||||
}
|
||||
|
||||
ui_space :: proc( label : string, flags : UI_BoxFlags = {} ) -> UI_Widget
|
||||
{
|
||||
// profile(#procedure)
|
||||
|
||||
space_str := str_intern( " " )
|
||||
|
||||
state := get_state(); using state
|
||||
|
||||
// TODO(Ed) : Move this somwhere in state.
|
||||
space_str := str_intern( " " )
|
||||
|
||||
box := ui_box_make( flags, label )
|
||||
signal := ui_signal_from_box( box )
|
||||
|
||||
box.text = space_str
|
||||
box.style.layout.size_to_text = true
|
||||
return { box, signal }
|
||||
}
|
||||
|
||||
ui_tab :: proc( label : string, flags : UI_BoxFlags = {} ) -> UI_Widget
|
||||
{
|
||||
// profile(#procedure)
|
||||
state := get_state(); using state
|
||||
|
||||
// TODO(Ed) : Move this somwhere in state.
|
||||
tab_str := str_intern( "\t" )
|
||||
|
||||
state := get_state(); using state
|
||||
|
||||
box := ui_box_make( flags, label )
|
||||
signal := ui_signal_from_box( box )
|
||||
|
||||
box.text = tab_str
|
||||
|
||||
box.style.layout.size_to_text = true
|
||||
return { box, signal }
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user