Cleanup and setup of drop down widget
Got an initial variant of the drop down widget, not completely set on it.. I put some more time to figuring out how I'm going to be ideomatically constructing the widgets. screen.odin I think its getting pretty close to what it will be like. I'm ready to start lifting the input box. I'll be adding the constraints when I lift it. Added the option to toggle the debug text in screenspace Added the fixes from the ui_layout_children_horizontally for margins to ui_layout_children_vertically Known issue: There is a bug with test_whitespace that forced me todo a null check on a box. Not sure why. It needs to be redone anyway.. (compose it with the h/vboxes instead) There is some sublime files added in, started to use it.
This commit is contained in:
		| @@ -113,8 +113,7 @@ ui_box_make :: proc( flags : UI_BoxFlags, label : string ) -> (^ UI_Box) | ||||
| 	curr_box.links          = {} | ||||
| 	curr_box.num_children   = 0 | ||||
|  | ||||
| 	// If there is a parent, setup the relevant references | ||||
| 	parent := stack_peek( & parent_stack ) | ||||
| 	parent := ui_parent_peek() | ||||
| 	if parent != nil | ||||
| 	{ | ||||
| 		dll_full_push_back( parent, curr_box, nil ) | ||||
|   | ||||
| @@ -160,10 +160,10 @@ ui_layout_peek :: #force_inline proc() ->  UI_LayoutCombo { return stack_peek( & | ||||
| ui_layout_ref  :: #force_inline proc() -> ^UI_LayoutCombo { return stack_peek_ref( & get_state().ui_context.layout_combo_stack) } | ||||
|  | ||||
| ui_layout_push_layout :: #force_inline proc( layout : UI_Layout )     { push( & get_state().ui_context.layout_combo_stack, to_ui_layout_combo(layout)) } | ||||
| ui_layout_push_theme  :: #force_inline proc( combo : UI_LayoutCombo ) { push( & get_state().ui_context.layout_combo_stack, combo ) } | ||||
| ui_layout_push_combo  :: #force_inline proc( combo : UI_LayoutCombo ) { push( & get_state().ui_context.layout_combo_stack, combo ) } | ||||
| ui_layout_pop         :: #force_inline proc()                         { pop(  & get_state().ui_context.layout_combo_stack ) } | ||||
|  | ||||
| @(deferred_none = ui_layout_pop) ui_layout_via_layout :: #force_inline proc( layout : UI_Layout )      { ui_layout_push( layout) } | ||||
| @(deferred_none = ui_layout_pop) ui_layout_via_combo  :: #force_inline proc( combo  : UI_LayoutCombo ) { ui_layout_push( combo) } | ||||
| @(deferred_none = ui_layout_pop) ui_layout_scope_via_layout :: #force_inline proc( layout : UI_Layout )      { ui_layout_push( layout) } | ||||
| @(deferred_none = ui_layout_pop) ui_layout_scope_via_combo  :: #force_inline proc( combo  : UI_LayoutCombo ) { ui_layout_push( combo) } | ||||
|  | ||||
| ui_set_layout :: #force_inline proc( layout : UI_Layout, preset : UI_StylePreset ) { stack_peek_ref( & get_state().ui_context.layout_combo_stack).array[preset] = layout } | ||||
|   | ||||
| @@ -274,6 +274,8 @@ ui_key_from_string :: #force_inline proc "contextless" ( value : string ) -> UI_ | ||||
| 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 ) } | ||||
|  | ||||
| ui_parent_peek :: #force_inline proc() -> ^UI_Box { return stack_peek( & ui_context().parent_stack )} | ||||
|  | ||||
| @(deferred_none = ui_parent_pop) | ||||
| ui_parent :: #force_inline proc( ui : ^UI_Box) { ui_parent_push( ui ) } | ||||
|  | ||||
|   | ||||
| @@ -66,7 +66,7 @@ ui_style_push_style :: #force_inline proc( style : UI_Style )      { push( & get | ||||
| ui_style_push_combo :: #force_inline proc( combo : UI_StyleCombo ) { push( & get_state().ui_context.style_combo_stack, combo ) } | ||||
| ui_style_pop        :: #force_inline proc()                        { pop(  & get_state().ui_context.style_combo_stack ) } | ||||
|  | ||||
| @(deferred_none = ui_style_pop) ui_style_via_style :: #force_inline proc( style : UI_Style )      { ui_style_push( style) } | ||||
| @(deferred_none = ui_style_pop) ui_style_via_combo :: #force_inline proc( combo : UI_StyleCombo ) { ui_style_push( combo) } | ||||
| @(deferred_none = ui_style_pop) ui_style_scope_via_style :: #force_inline proc( style : UI_Style )      { ui_style_push( style) } | ||||
| @(deferred_none = ui_style_pop) ui_style_scope_via_combo :: #force_inline proc( combo : UI_StyleCombo ) { ui_style_push( combo) } | ||||
|  | ||||
| ui_style_set :: #force_inline proc ( style : UI_Style, preset : UI_StylePreset ) { stack_peek_ref( & get_state().ui_context.style_combo_stack ).array[preset] = style } | ||||
|   | ||||
| @@ -10,28 +10,36 @@ UI_Theme :: struct { | ||||
| 	style  : UI_StyleCombo, | ||||
| } | ||||
|  | ||||
| ui_theme_push_via_proc :: #force_inline proc( procedure : #type proc() -> UI_Theme ) { ui_theme_push(procedure()) } | ||||
| ui_theme_push_via_theme ::#force_inline proc( theme : UI_Theme ) { | ||||
| 	ui_layout_push( theme.layout ) | ||||
| 	ui_style_push( theme.style ) | ||||
| } | ||||
|  | ||||
| ui_theme_pop :: #force_inline proc() { | ||||
| 	ui_layout_pop() | ||||
| 	ui_style_pop() | ||||
| } | ||||
|  | ||||
| @(deferred_none = ui_theme_pop) | ||||
| ui_theme_via_layout_style :: #force_inline proc( layout : UI_Layout, style : UI_Style ) { | ||||
| ui_theme_scope_via_layout_style :: #force_inline proc( layout : UI_Layout, style : UI_Style ) { | ||||
| 	using ui := get_state().ui_context | ||||
| 	ui_layout_push( layout ) | ||||
| 	ui_style_push( style ) | ||||
| } | ||||
|  | ||||
| @(deferred_none = ui_theme_pop) | ||||
| ui_theme_via_combos :: #force_inline proc( layout : UI_LayoutCombo, style : UI_StyleCombo ) { | ||||
| ui_theme_scope_via_combos :: #force_inline proc( layout : UI_LayoutCombo, style : UI_StyleCombo ) { | ||||
| 	using ui := get_state().ui_context | ||||
| 	ui_layout_push( layout ) | ||||
| 	ui_style_push( style ) | ||||
| } | ||||
|  | ||||
| @(deferred_none = ui_theme_pop) | ||||
| ui_theme_via_theme :: #force_inline proc( theme : UI_Theme ) { | ||||
| ui_theme_scope_via_proc :: #force_inline proc( procedure : #type proc() -> UI_Theme ) { ui_theme_push(procedure()) } | ||||
|  | ||||
| @(deferred_none = ui_theme_pop) | ||||
| ui_theme_scope_via_theme :: #force_inline proc( theme : UI_Theme ) { | ||||
| 	using ui := get_state().ui_context | ||||
| 	ui_layout_push( theme.layout ) | ||||
| 	ui_style_push( theme.style ) | ||||
| 	ui_theme_push(theme) | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| package sectr | ||||
|  | ||||
| import "base:runtime" | ||||
| import lalg "core:math/linalg" | ||||
|  | ||||
| /* | ||||
| Widget Layout Ops | ||||
| @@ -35,6 +36,7 @@ ui_layout_children_horizontally :: proc( container : ^UI_Box, direction : UI_Lay | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		size_req_children   += size.min.x | ||||
| 		total_stretch_ratio += anchor.ratio.x | ||||
| 	} | ||||
|  | ||||
| @@ -48,14 +50,15 @@ ui_layout_children_horizontally :: proc( container : ^UI_Box, direction : UI_Lay | ||||
| 			space_allocated = size.min.x * container_height | ||||
| 		} | ||||
| 		else if ! (.Fixed_Width in flags) { | ||||
| 			size.min.x      = anchor.ratio.x * (1 / total_stretch_ratio) * avail_flex_space | ||||
| 			space_allocated = size.min.x | ||||
| 			potential_size  := anchor.ratio.x * (1 / total_stretch_ratio) * avail_flex_space | ||||
| 			space_allocated  = lalg.max(potential_size, size.min.x) | ||||
| 			size.min.x       = space_allocated | ||||
| 		} | ||||
| 		else { | ||||
| 			space_allocated = size.min.x | ||||
| 		} | ||||
| 		space_allocated -= child.layout.margins.left - child.layout.margins.right | ||||
| 		size.min.x      -= child.layout.margins.left - child.layout.margins.right | ||||
| 		space_allocated -= margins.left - margins.right | ||||
| 		size.min.x      -= margins.left - margins.right | ||||
| 		flags |= {.Fixed_Width} | ||||
| 		return | ||||
| 	} | ||||
| @@ -67,7 +70,6 @@ ui_layout_children_horizontally :: proc( container : ^UI_Box, direction : UI_Lay | ||||
| 				using child.layout | ||||
| 				child_width := allocate_space(child, total_stretch_ratio, avail_flex_space, container_height) | ||||
| 				anchor       = range2({0, 0}, {0, 0}) | ||||
| 				width : f32 | ||||
| 				pos.x        = space_used | ||||
| 				space_used  += child_width + child.layout.margins.left + child.layout.margins.right | ||||
| 			} | ||||
| @@ -76,7 +78,6 @@ ui_layout_children_horizontally :: proc( container : ^UI_Box, direction : UI_Lay | ||||
| 				using child.layout | ||||
| 				child_width := allocate_space(child, total_stretch_ratio, avail_flex_space, container_height) | ||||
| 				anchor       = range2({0, 0}, {0, 0}) | ||||
| 				width : f32 | ||||
| 				pos.x        = space_used | ||||
| 				space_used  += child_width + child.layout.margins.left + child.layout.margins.right | ||||
| 			} | ||||
| @@ -92,6 +93,7 @@ ui_layout_children_vertically :: proc( container : ^UI_Box, direction : UI_Layou | ||||
| 	else { | ||||
| 		container_height = container.computed.content.max.y - container.computed.content.min.y | ||||
| 	} | ||||
| 	container_width := container.computed.content.max.x - container.computed.content.min.x | ||||
|  | ||||
| 	// do layout calculations for the children | ||||
| 	total_stretch_ratio : f32 = 0.0 | ||||
| @@ -99,33 +101,42 @@ ui_layout_children_vertically :: proc( container : ^UI_Box, direction : UI_Layou | ||||
| 	for child := container.first; child != nil; child = child.next | ||||
| 	{ | ||||
| 		using child.layout | ||||
| 		scaled_width_by_height : b32 = b32(.Scale_Width_By_Height_Ratio in flags) | ||||
| 		scaled_height_by_width : b32 = b32(.Scale_Height_By_Width_Ratio in flags) | ||||
| 		if scaled_height_by_width { | ||||
| 			size_req_children += size.min.y * container_width | ||||
| 			continue | ||||
| 		} | ||||
| 		if .Fixed_Height in flags | ||||
| 		{ | ||||
| 			if scaled_width_by_height { | ||||
| 				width  := size.max.x != 0 ? size.max.x : container_height | ||||
| 				height := width * size.min.y | ||||
|  | ||||
| 				size_req_children += height | ||||
| 				continue | ||||
| 			} | ||||
|  | ||||
| 			size_req_children += size.min.y | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		size_req_children   += size.min.y | ||||
| 		total_stretch_ratio += anchor.ratio.y | ||||
| 	} | ||||
|  | ||||
| 	avail_flex_space := container_height - size_req_children | ||||
|  | ||||
| 	allocate_space :: proc( child : ^UI_Box, total_stretch_ratio, avail_flex_space : f32 ) | ||||
| 	allocate_space :: proc( child : ^UI_Box, total_stretch_ratio, avail_flex_space, container_width : f32 ) -> (space_allocated : f32) | ||||
| 	{ | ||||
| 		using child.layout | ||||
| 		if ! (.Fixed_Height in flags) { | ||||
| 			size.min.y = (anchor.ratio.y * (1 / total_stretch_ratio) * avail_flex_space) | ||||
| 		if .Scale_Height_By_Width_Ratio in flags { | ||||
| 			size.min.x      = container_width | ||||
| 			space_allocated = size.min.y * container_width | ||||
| 		} | ||||
| 		if ! (.Fixed_Height in flags) { | ||||
| 			potential_size  := (anchor.ratio.y * (1 / total_stretch_ratio) * avail_flex_space) | ||||
| 			space_allocated  = lalg.max(potential_size, size.min.y) | ||||
| 			size.min.y       = space_allocated | ||||
| 		} | ||||
| 		else { | ||||
| 			space_allocated = size.min.y | ||||
| 		} | ||||
| 		space_allocated -= margins.top - margins.bottom | ||||
| 		size.min.y      -= margins.top - margins.bottom | ||||
| 		flags |= {.Fixed_Height} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	space_used : f32 = 0.0 | ||||
| @@ -133,21 +144,19 @@ ui_layout_children_vertically :: proc( container : ^UI_Box, direction : UI_Layou | ||||
| 	{ | ||||
| 		case .Bottom_To_Top: | ||||
| 			for child := container.last; child != nil; child = child.prev { | ||||
| 				allocate_space(child, total_stretch_ratio, avail_flex_space) | ||||
| 				using child.layout | ||||
| 				anchor      = range2({0,0}, {0, 0}) | ||||
| 				pos.y       = -space_used | ||||
| 				space_used += size.min.y + child.layout.margins.top + child.layout.margins.bottom | ||||
| 				size.min.x  = container.computed.content.max.x + container.computed.content.min.x | ||||
| 				child_height := allocate_space(child, total_stretch_ratio, avail_flex_space, container_width) | ||||
| 				anchor        = range2({0,0}, {0, 0}) | ||||
| 				pos.y         = -space_used | ||||
| 				space_used   += child_height + child.layout.margins.top + child.layout.margins.bottom | ||||
| 			} | ||||
| 		case .Top_To_Bottom: | ||||
| 			for child := container.first; child != nil; child = child.next { | ||||
| 				allocate_space(child, total_stretch_ratio, avail_flex_space) | ||||
| 				using child.layout | ||||
| 				child_height := allocate_space(child, total_stretch_ratio, avail_flex_space, container_width) | ||||
| 				anchor      = range2({0, 0}, {0, 0}) | ||||
| 				pos.y       = -space_used | ||||
| 				space_used += size.min.y + child.layout.margins.top + child.layout.margins.bottom | ||||
| 				size.min.x  = container.computed.content.max.x - container.computed.content.min.x | ||||
| 				space_used += child_height + child.layout.margins.top + child.layout.margins.bottom | ||||
| 			} | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -8,6 +8,7 @@ test_hover_n_click :: proc() | ||||
| 	state := get_state(); using state | ||||
|  | ||||
| 	first_btn := ui_button( "FIRST BOX!" ) | ||||
| 	first_btn.layout.size.min = {1000, 1000} | ||||
| 	if first_btn.left_clicked || debug.frame_2_created { | ||||
| 		debug.frame_2_created = true | ||||
|  | ||||
| @@ -37,8 +38,8 @@ test_draggable :: proc() | ||||
| 		pos       = { 0, 0 }, | ||||
| 		size      = range2({ 200, 200 }, {}), | ||||
| 	} | ||||
| 	ui_layout( draggable_layout ) | ||||
| 	ui_style( UI_Style { | ||||
| 	scope( draggable_layout ) | ||||
| 	scope( UI_Style { | ||||
| 		corner_radii = { 0.3, 0.3, 0.3, 0.3 }, | ||||
| 	}) | ||||
|  | ||||
| @@ -82,10 +83,10 @@ test_parenting :: proc( default_layout : ^UI_Layout, frame_style_default : ^UI_S | ||||
| 		.Fixed_Width, .Fixed_Height, | ||||
| 		.Origin_At_Anchor_Center | ||||
| 	} | ||||
| 	ui_layout(parent_layout) | ||||
| 	scope(parent_layout) | ||||
|  | ||||
| 	parent_style := frame_style_default ^ | ||||
| 	ui_style(parent_style) | ||||
| 	scope(parent_style) | ||||
|  | ||||
| 	parent :=	ui_widget( "Parent", { .Mouse_Clickable }) | ||||
| 	ui_parent_push(parent) | ||||
| @@ -107,7 +108,7 @@ test_parenting :: proc( default_layout : ^UI_Layout, frame_style_default : ^UI_S | ||||
|  | ||||
| 	child_layout := default_layout ^ | ||||
| 	child_layout.size      = range2({ 100, 100 }, { 0, 0 }) | ||||
| 	child_layout.alignment = { 0.0, 0.0 } | ||||
| 	child_layout.alignment = { 1.0, 0.0 } | ||||
| 	// child_layout.margins   = { 20, 20, 20, 20 } | ||||
| 	child_layout.padding   = { 5, 5, 5, 5 } | ||||
| 	// child_layout.anchor    = range2({ 0.2, 0.1 }, { 0.1, 0.15 }) | ||||
| @@ -119,7 +120,7 @@ test_parenting :: proc( default_layout : ^UI_Layout, frame_style_default : ^UI_S | ||||
|  | ||||
| 	child_style := frame_style_default ^ | ||||
| 	child_style.bg_color = Color_GreyRed | ||||
| 	ui_theme(child_layout, child_style) | ||||
| 	scope(child_layout, child_style) | ||||
| 	child := ui_widget( "Child", { .Mouse_Clickable }) | ||||
| 	ui_parent_pop() | ||||
| } | ||||
| @@ -174,7 +175,7 @@ test_whitespace_ast :: proc( default_layout : ^UI_Layout, frame_style_default : | ||||
| 	text_style_combo.disabled.bg_color = Color_Frame_Disabled | ||||
| 	text_style_combo.hot.bg_color      = Color_Frame_Hover | ||||
| 	text_style_combo.active.bg_color   = Color_Frame_Select | ||||
| 	ui_theme( text_layout, text_style ) | ||||
| 	scope( text_layout, text_style ) | ||||
|  | ||||
| 	alloc_error : AllocatorError; success : bool | ||||
| 	// debug.lorem_content, success = os.read_entire_file( debug.path_lorem, frame_allocator() ) | ||||
| @@ -216,7 +217,7 @@ test_whitespace_ast :: proc( default_layout : ^UI_Layout, frame_style_default : | ||||
| 			chunk_layout.flags     = { .Fixed_Position_X, .Size_To_Text } | ||||
|  | ||||
| 			chunk_style := text_style | ||||
| 			ui_theme( to_ui_layout_combo(chunk_layout), to_ui_style_combo(chunk_style) ) | ||||
| 			scope( chunk_layout, chunk_style ) | ||||
|  | ||||
| 			head := line.first | ||||
| 			for ; head != nil; | ||||
| @@ -289,7 +290,10 @@ test_whitespace_ast :: proc( default_layout : ^UI_Layout, frame_style_default : | ||||
| 			text_layout.pos.y += size_range2(line_hbox.computed.bounds).y | ||||
| 		} | ||||
| 		else { | ||||
| 			text_layout.pos.y += size_range2( (& widgets.data[ widgets.num - 1 ]).computed.bounds ).y | ||||
| 			widget := & widgets.data[ widgets.num - 1 ] | ||||
| 			if widget.box != nil { | ||||
| 				text_layout.pos.y += size_range2( widget.computed.bounds ).y | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		line_id += 1 | ||||
|   | ||||
| @@ -3,6 +3,9 @@ package sectr | ||||
| import "base:runtime" | ||||
| import lalg "core:math/linalg" | ||||
|  | ||||
| // Problably cursed way to setup a 'scope' for a widget | ||||
| ui_build :: #force_inline proc( captures : $Type, $maker : #type proc(captures : Type) -> $ReturnType ) -> ReturnType { return maker(captures) } | ||||
|  | ||||
| UI_Widget :: struct { | ||||
| 	using box    : ^UI_Box, | ||||
| 	using signal : UI_Signal, | ||||
| @@ -23,6 +26,80 @@ ui_button :: proc( label : string, flags : UI_BoxFlags = {} ) -> (btn : UI_Widge | ||||
| 	return | ||||
| } | ||||
|  | ||||
| #region("Drop Down") | ||||
| /* TODO(Ed): Don't feel very good about the abstraction... | ||||
| */ | ||||
| UI_DropDown :: struct { | ||||
| 	btn     : UI_Widget, | ||||
| 	title   : UI_Widget, | ||||
| 	vbox    : UI_VBox, | ||||
| 	is_open : bool, | ||||
| } | ||||
|  | ||||
| @(deferred_out = ui_drop_down_end_auto) | ||||
| ui_drop_down :: proc( drop_down : ^UI_DropDown, label : string, title_text : StrRunesPair, | ||||
| 	direction         := UI_LayoutDirectionY.Top_To_Bottom, | ||||
| 	btn_flags         := UI_BoxFlags{}, | ||||
| 	vb_flags          := UI_BoxFlags{}, | ||||
| 	vb_compute_layout := true, | ||||
| 	btn_theme   : ^UI_Theme = nil, | ||||
| 	title_theme : ^UI_Theme = nil | ||||
| ) -> (deferred : ^UI_DropDown) | ||||
| { | ||||
| 	deferred = drop_down | ||||
| 	ui_drop_down_begin(drop_down, label, title_text, direction, btn_flags, vb_flags, btn_theme, title_theme) | ||||
| 	if ! drop_down.is_open do return | ||||
| 	ui_parent_push(drop_down.vbox) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // Its assumed that the drop down has a vertical box parent already pushed | ||||
| ui_drop_down_begin :: proc( drop_down : ^UI_DropDown, label : string, title_text : StrRunesPair, | ||||
| 	direction := UI_LayoutDirectionY.Top_To_Bottom, | ||||
| 	btn_flags := UI_BoxFlags{}, | ||||
| 	vb_flags  := UI_BoxFlags{}, | ||||
| 	btn_theme   : ^UI_Theme = nil, | ||||
| 	title_theme : ^UI_Theme = nil, | ||||
| 	vb_compute_layout := true ) | ||||
| { | ||||
| 	using drop_down | ||||
|  | ||||
| 	if btn_theme == nil do push(theme_drop_down_btn) | ||||
| 	else                do push(btn_theme ^) | ||||
| 	defer                  ui_theme_pop() | ||||
| 	btn = ui_button( str_intern_fmt("%s.btn", label).str ); | ||||
| 	{ | ||||
| 		btn.layout.padding.left = 4 | ||||
| 		ui_parent(btn) | ||||
|  | ||||
| 		if title_theme == nil do push(theme_text) | ||||
| 		else                  do push(title_theme ^) | ||||
| 		defer                    ui_theme_pop() | ||||
| 		title = ui_text( str_intern_fmt("%s.btn.title", label).str, title_text) | ||||
| 	} | ||||
|  | ||||
| 	if btn.pressed { | ||||
| 		is_open = !is_open | ||||
| 	} | ||||
| 	if is_open == false do return | ||||
|  | ||||
| 	scope(theme_transparent) | ||||
| 	vbox = ui_vbox_begin( direction, str_intern_fmt("%v : vbox", label).str, compute_layout = vb_compute_layout ) | ||||
| 	vbox.layout.anchor.ratio.y = 1.0 | ||||
| } | ||||
|  | ||||
| ui_drop_down_end :: proc( drop_down : ^UI_DropDown ) { | ||||
| 	if ! drop_down.is_open do return | ||||
| 	ui_vbox_end(drop_down.vbox) | ||||
| } | ||||
|  | ||||
| ui_drop_down_end_auto :: proc( drop_down : ^UI_DropDown) { | ||||
| 	if ! drop_down.is_open do return | ||||
| 	ui_vbox_end(drop_down.vbox, compute_layout = true) | ||||
| 	ui_parent_pop() | ||||
| } | ||||
| #endregion("Drop Down") | ||||
|  | ||||
| #region("Horizontal Box") | ||||
| /* | ||||
| Horizontal Boxes automatically manage a collection of widgets and | ||||
| @@ -39,13 +116,11 @@ The hbox will use the anchor's (range2) ratio.x value to determine the "stretch | ||||
| Keep in mind the stretch ratio is only respected if no size.min.x value is violated for each of the widgets. | ||||
| */ | ||||
|  | ||||
| // Horizontal Widget | ||||
| UI_HBox :: struct { | ||||
| 	using widget : UI_Widget, | ||||
| 	direction    : UI_LayoutDirectionX, | ||||
| } | ||||
|  | ||||
| // Boilerplate creation | ||||
| ui_hbox_begin :: proc( direction : UI_LayoutDirectionX, label : string, flags : UI_BoxFlags = {} ) -> (hbox : UI_HBox) { | ||||
| 	// profile(#procedure) | ||||
| 	hbox.direction = direction | ||||
| @@ -171,7 +246,6 @@ ui_resizable_handles :: proc( parent : ^UI_Widget, pos : ^Vec2, size : ^Vec2, | ||||
| 	handle_corner_tl : UI_Widget | ||||
| 	handle_corner_br : UI_Widget | ||||
| 	handle_corner_bl : UI_Widget | ||||
| 	ui_parent(parent) | ||||
|  | ||||
| 	@(deferred_none = ui_theme_pop) | ||||
| 	theme_handle :: proc( base : ^UI_Theme, margins, size : Vec2, flags : UI_LayoutFlags = {}) | ||||
| @@ -247,50 +321,52 @@ ui_resizable_handles :: proc( parent : ^UI_Widget, pos : ^Vec2, size : ^Vec2, | ||||
| 	} | ||||
| 	context.user_ptr = & parent.label | ||||
|  | ||||
| 	#region("Handle & Corner construction") | ||||
| 	theme_handle( theme, {handle_width, 0}, {handle_width,0}) | ||||
| 	if left { | ||||
| 		handle_left = ui_widget(name("resize_handle_left"), flags ) | ||||
| 		handle_left.layout.anchor.left  = 0 | ||||
| 		handle_left.layout.anchor.right = 1 | ||||
| 		handle_left.layout.alignment    = {1, 0} | ||||
| 	Handle_Construction: | ||||
| 	{ | ||||
| 		ui_parent(parent) | ||||
| 		theme_handle( theme, {handle_width, 0}, {handle_width,0}) | ||||
| 		if left { | ||||
| 			handle_left = ui_widget(name("resize_handle_left"), flags ) | ||||
| 			handle_left.layout.anchor.left  = 0 | ||||
| 			handle_left.layout.anchor.right = 1 | ||||
| 			handle_left.layout.alignment    = {1, 0} | ||||
| 		} | ||||
| 		if right { | ||||
| 			handle_right = ui_widget(name("resize_handle_right"), flags ) | ||||
| 			handle_right.layout.anchor.left = 1 | ||||
| 		} | ||||
| 		theme_handle( theme, {0, handle_width}, {0, handle_width}) | ||||
| 		if top { | ||||
| 			handle_top = ui_widget(name("resize_handle_top"), flags ) | ||||
| 			handle_top.layout.anchor.bottom = 1 | ||||
| 			handle_top.layout.alignment     = {0, -1} | ||||
| 		} | ||||
| 		if bottom { | ||||
| 			handle_bottom = ui_widget("resize_handle_bottom", flags) | ||||
| 			handle_bottom.layout.anchor.top  = 1 | ||||
| 			handle_bottom.layout.alignment   = { 0, 0 } | ||||
| 		} | ||||
| 		theme_handle( theme, {0,0}, {handle_width, handle_width}, {.Fixed_Width, .Fixed_Height} ) | ||||
| 		if corner_tl { | ||||
| 			handle_corner_tl = ui_widget(name("corner_top_left"), flags) | ||||
| 			handle_corner_tl.layout.alignment = {1, -1} | ||||
| 		} | ||||
| 		if corner_tr { | ||||
| 			handle_corner_tr = ui_widget(name("corner_top_right"), flags) | ||||
| 			handle_corner_tr.layout.anchor    = range2({1, 0}, {}) | ||||
| 			handle_corner_tr.layout.alignment = {0, -1} | ||||
| 		} | ||||
| 		if corner_bl { | ||||
| 			handle_corner_bl = ui_widget("corner_bottom_left", flags) | ||||
| 			handle_corner_bl.layout.anchor    = range2({}, {0, 1}) | ||||
| 			handle_corner_bl.layout.alignment = { 1, 0 } | ||||
| 		} | ||||
| 		if corner_br { | ||||
| 			handle_corner_br = ui_widget("corner_bottom_right", flags) | ||||
| 			handle_corner_br.layout.anchor    = range2({1, 0}, {0, 1}) | ||||
| 			handle_corner_br.layout.alignment = {0, 0} | ||||
| 		} | ||||
| 	} | ||||
| 	if right { | ||||
| 		handle_right = ui_widget(name("resize_handle_right"), flags ) | ||||
| 		handle_right.layout.anchor.left = 1 | ||||
| 	} | ||||
| 	theme_handle( theme, {0, handle_width}, {0, handle_width}) | ||||
| 	if top { | ||||
| 		handle_top = ui_widget(name("resize_handle_top"), flags ) | ||||
| 		handle_top.layout.anchor.bottom = 1 | ||||
| 		handle_top.layout.alignment     = {0, -1} | ||||
| 	} | ||||
| 	if bottom { | ||||
| 		handle_bottom = ui_widget("resize_handle_bottom", flags) | ||||
| 		handle_bottom.layout.anchor.top  = 1 | ||||
| 		handle_bottom.layout.alignment   = { 0, 0 } | ||||
| 	} | ||||
| 	theme_handle( theme, {0,0}, {handle_width, handle_width}, {.Fixed_Width, .Fixed_Height} ) | ||||
| 	if corner_tl { | ||||
| 		handle_corner_tl = ui_widget(name("corner_top_left"), flags) | ||||
| 		handle_corner_tl.layout.alignment = {1, -1} | ||||
| 	} | ||||
| 	if corner_tr { | ||||
| 		handle_corner_tr = ui_widget(name("corner_top_right"), flags) | ||||
| 		handle_corner_tr.layout.anchor    = range2({1, 0}, {}) | ||||
| 		handle_corner_tr.layout.alignment = {0, -1} | ||||
| 	} | ||||
| 	if corner_bl { | ||||
| 		handle_corner_bl = ui_widget("corner_bottom_left", flags) | ||||
| 		handle_corner_bl.layout.anchor    = range2({}, {0, 1}) | ||||
| 		handle_corner_bl.layout.alignment = { 1, 0 } | ||||
| 	} | ||||
| 	if corner_br { | ||||
| 		handle_corner_br = ui_widget("corner_bottom_right", flags) | ||||
| 		handle_corner_br.layout.anchor    = range2({1, 0}, {0, 1}) | ||||
| 		handle_corner_br.layout.alignment = {0, 0} | ||||
| 	} | ||||
| 	#endregion("Handle & Corner construction") | ||||
|  | ||||
| 	process_handle_drag :: #force_inline proc ( handle : ^UI_Widget, | ||||
| 		direction                :  Vec2, | ||||
| @@ -319,8 +395,6 @@ ui_resizable_handles :: proc( parent : ^UI_Widget, pos : ^Vec2, size : ^Vec2, | ||||
|  | ||||
| 		shift_changed := (left_shift_held != prev_left_shift_held) | ||||
|  | ||||
| 		need_to_change_alignment_and_pos := pressed || shift_changed | ||||
|  | ||||
| 		if active | ||||
| 		{ | ||||
| 			if pressed | ||||
| @@ -379,8 +453,6 @@ ui_resizable_handles :: proc( parent : ^UI_Widget, pos : ^Vec2, size : ^Vec2, | ||||
| 			was_dragging   = false | ||||
| 			start_size     = 0 | ||||
| 		} | ||||
| 		// text = active_context.root.label | ||||
| 		// style.text_color = Color_White | ||||
|  | ||||
| 		prev_left_shift_held = handle.left_shift_held | ||||
| 		prev_alignment       = align_adjsutment | ||||
| @@ -433,14 +505,13 @@ UI_ScrollBox :: struct { | ||||
| } | ||||
|  | ||||
| ui_scroll_box :: proc( label : string, flags : UI_BoxFlags ) -> (scroll_box : UI_ScrollBox) { | ||||
| 	fatal("NOT IMPLEMENTED") | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // ui_scrollable_view(  ) | ||||
|  | ||||
| #region("Text") | ||||
|  | ||||
| ui_text :: proc( label : string, content : StrRunesPair, flags : UI_BoxFlags = {} ) -> UI_Widget | ||||
| { | ||||
| 	// profile(#procedure) | ||||
| @@ -510,7 +581,6 @@ UI_VBox :: struct { | ||||
| 	direction    : UI_LayoutDirectionY, | ||||
| } | ||||
|  | ||||
| // Boilerplate creation | ||||
| ui_vbox_begin :: proc( direction : UI_LayoutDirectionY, label : string, flags : UI_BoxFlags = {}, compute_layout := false ) -> (vbox : UI_VBox) { | ||||
| 	// profile(#procedure) | ||||
| 	vbox.direction = direction | ||||
|   | ||||
		Reference in New Issue
	
	Block a user