Preparing skeleton for proper imgui support.
I originally wanted to reference Ryan's UI series along with the RAD Debugger codebase, but that ended up being too convoluted of a route. Instead, I moved on to just doing a deep dive on imgui content I could find to learn from and associated libraries available. I collected my notes so far in this repo [IMGUI_Notes](https://github.com/Ed94/IMGUI_Notes). For now I have the base scaffolding datatype wise for the prototype ui.
This commit is contained in:
		
							
								
								
									
										275
									
								
								code/__Imgui_raddbg/ui.odin
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										275
									
								
								code/__Imgui_raddbg/ui.odin
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,275 @@ | ||||
| package wip | ||||
|  | ||||
| // Based off Ryan Fleury's UI Series & Epic's RAD Debugger which directly implements a version of it. | ||||
| // You will see Note(rjf) these are comments directly from the RAD Debugger codebase by Fleury. | ||||
| // TODO(Ed) If I can, I would like this to be its own package, but the nature of packages in odin may make this difficult. | ||||
|  | ||||
| // TODO(Ed) : This is in Raddbg base_types.h, consider moving outside of UI. | ||||
| Axis2 :: enum i32 { | ||||
| 	Invalid = -1, | ||||
| 	X       = 0, | ||||
| 	Y       = 1, | ||||
| 	Count, | ||||
| } | ||||
|  | ||||
| Corner :: enum i32 { | ||||
| 	Invalid = -1, | ||||
| 	_00, | ||||
| 	_01, | ||||
| 	_10, | ||||
| 	_11, | ||||
| 	TopLeft     = _00, | ||||
| 	TopRight    = _01, | ||||
| 	BottomLeft  = _10, | ||||
| 	BottomRight = _11, | ||||
| 	Count = 4, | ||||
| } | ||||
|  | ||||
| // TODO(Ed) : From Raddbg draw.h, consider if needed or covered by raylib. | ||||
| DrawBucket :: struct { | ||||
| 	// passes : RenderPassList, | ||||
| 	stack_gen : u64, | ||||
| 	last_cmd_stack_gen : u64, | ||||
| 	// DrawBucketStackDeclares | ||||
| } | ||||
|  | ||||
| // TODO(Ed) : From Raddbg draw.h, consider if needed or covered by raylib. | ||||
| DrawFancyRunList :: struct { | ||||
| 	placeholder : int | ||||
| } | ||||
|  | ||||
| // TODO(Ed) : From Raddbg base_string.h, consider if needed or covered by raylib. | ||||
| FuzzyMatchRangeList :: struct { | ||||
| 	placeholder : int | ||||
| } | ||||
|  | ||||
| // TODO(Ed): This is in Raddbg os_gfx.h, consider moving outside of UI. | ||||
| OS_Cursor :: enum u32 { | ||||
| 	Pointer, | ||||
| 	IBar, | ||||
| 	Left_Right, | ||||
| 	Up_Down, | ||||
| 	Down_Right, | ||||
| 	Up_Right, | ||||
| 	Up_Down_left_Right, | ||||
| 	Hand_Point, | ||||
| 	Disabled, | ||||
| 	Count, | ||||
| } | ||||
|  | ||||
| Range2 :: struct #raw_union{ | ||||
| 	using _ : struct { | ||||
| 		min, max : Vec2 | ||||
| 	}, | ||||
| 	using _ : struct { | ||||
| 		p0, p1 : Vec2 | ||||
| 	}, | ||||
| 	using _ : struct { | ||||
| 		x0, y0 : f32, | ||||
| 		x1, y1 : f32, | ||||
| 	}, | ||||
| } | ||||
|  | ||||
| Side :: enum i32 { | ||||
| 	Invalid = -1, | ||||
| 	Min     = 0, | ||||
| 	Max     = 1, | ||||
| 	Count | ||||
| } | ||||
|  | ||||
| UI_FocusKind :: enum u32 { | ||||
| 	Null, | ||||
| 	Off, | ||||
| 	On, | ||||
| 	Root, | ||||
| 	Count, | ||||
| } | ||||
|  | ||||
| UI_IconKind :: enum u32 { | ||||
| 	Null, | ||||
| 	Arrow_Up, | ||||
| 	Arrow_Left, | ||||
| 	Arrow_Right, | ||||
| 	Arrow_Down, | ||||
| 	Caret_Up, | ||||
| 	Caret_Left, | ||||
| 	Caret_Right, | ||||
| 	Caret_Down, | ||||
| 	Check_Hollow, | ||||
| 	Check_Filled, | ||||
| 	Count, | ||||
| } | ||||
|  | ||||
| UI_IconInfo :: struct { | ||||
| 	placehodler : int | ||||
| } | ||||
|  | ||||
| UI_Key :: struct { | ||||
| 	opaque : [1]u64, | ||||
| } | ||||
|  | ||||
| UI_Layout :: struct { | ||||
| 	placeholder : int | ||||
| } | ||||
|  | ||||
| UI_Nav :: struct { | ||||
| 	moved : b32, | ||||
| 	new_p : Vec2i | ||||
| } | ||||
|  | ||||
| UI_NavDeltaUnit :: enum u32 { | ||||
| 	Element, | ||||
| 	Chunk, | ||||
| 	Whole, | ||||
| 	End_Point, | ||||
| 	Count, | ||||
| } | ||||
|  | ||||
| UI_NavActionFlag :: enum u32 { | ||||
| 	Keep_Mark, | ||||
| 	Delete, | ||||
| 	Copy, | ||||
| 	Paste, | ||||
| 	Zero_Delta_On_Select, | ||||
| 	Pick_Select_Side, | ||||
| 	Can_At_Line, | ||||
| 	Explicit_Directional, | ||||
| 	Replace_And_Commit, | ||||
| } | ||||
| UI_NavActionFlags :: bit_set[UI_NavActionFlag; u32] | ||||
|  | ||||
| UI_NavAction :: struct { | ||||
| 	flags      : UI_NavActionFlags, | ||||
| 	delta      : Vec2i, | ||||
| 	delta_unit : UI_NavDeltaUnit, | ||||
| 	insertion  : string, | ||||
| } | ||||
|  | ||||
| UI_NavActionNode :: struct { | ||||
| 	next   : ^ UI_NavActionNode, | ||||
| 	last   : ^ UI_NavActionNode, | ||||
| 	action : UI_NavAction | ||||
| } | ||||
|  | ||||
| UI_NavActionList :: struct { | ||||
| 	first : ^ UI_NavActionNode, | ||||
| 	last  : ^ UI_NavActionNode, | ||||
| 	count : u64, | ||||
| } | ||||
|  | ||||
| UI_NavTextOpFlag :: enum u32 { | ||||
| 	Invalid, | ||||
| 	Copy, | ||||
| } | ||||
| UI_NavTextOpFlags :: bit_set[UI_NavTextOpFlag; u32] | ||||
|  | ||||
| UI_ScrollPt :: struct { | ||||
| 	idx    : i64, | ||||
| 	offset : f32 | ||||
| } | ||||
| UI_ScrollPt2 :: [2]UI_ScrollPt | ||||
|  | ||||
| UI_Signal :: struct { | ||||
| 	box : UI_Box, | ||||
|  | ||||
| 	cursor_pos : Vec2, | ||||
| 	drag_delta : Vec2, | ||||
| 	scroll     : Vec2, | ||||
|  | ||||
| 	left_clicked     : b8, | ||||
| 	right_clicked    : b8, | ||||
| 	double_clicked   : b8, | ||||
| 	keyboard_clicked : b8, | ||||
|  | ||||
| 	pressed    : b8, | ||||
| 	released   : b8, | ||||
| 	dragging   : b8, | ||||
| 	hovering   : b8, | ||||
| 	mouse_over : b8, | ||||
| 	commit     : b8, | ||||
| } | ||||
|  | ||||
| UI_SizeKind :: enum u32 { | ||||
| 	Null, | ||||
| 	Pixels, | ||||
| 	Points, | ||||
| 	TextContent, | ||||
| 	PercentOfParent, | ||||
| 	ChildrenSum, | ||||
| 	Count, | ||||
| } | ||||
|  | ||||
| UI_Size :: struct { | ||||
| 	kind       : UI_SizeKind, | ||||
| 	value      : f32, | ||||
| 	strictness : f32, | ||||
| } | ||||
|  | ||||
| UI_Size2 : struct { | ||||
| 	kind       : [Axis2.Count]UI_SizeKind, | ||||
| 	value      : Vec2, | ||||
| 	strictness : Vec2, | ||||
| } | ||||
|  | ||||
| UI_TextAlign :: enum u32 { | ||||
| 	Left, | ||||
| 	Center, | ||||
| 	Right, | ||||
| 	Count | ||||
| } | ||||
|  | ||||
| ui_key_null :: proc() -> UI_Key { | ||||
| 	return {} | ||||
| } | ||||
|  | ||||
| ui_key_from_string :: proc( value : string ) -> UI_Key { | ||||
| 	 return {} | ||||
| } | ||||
|  | ||||
| ui_key_match :: proc( a, b : UI_Key ) -> b32 { | ||||
| 	 return false | ||||
| } | ||||
|  | ||||
| ui_box_make :: proc( flags : UI_BoxFlags, label : string ) -> (^ UI_Box) { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| ui_box_equip_display_string :: proc( box : ^ UI_Box, display_string : string ) { | ||||
|  | ||||
| } | ||||
|  | ||||
| ui_box_equip_child_layout_axis :: proc( box : ^ UI_Box, axis : Axis2 ) { | ||||
|  | ||||
| } | ||||
|  | ||||
| ui_push_parent :: proc( box : ^ UI_Box ) -> (^ UI_Box) { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| ui_pop_parent :: proc() -> (^ UI_Box) { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| ui_signal_from_box :: proc( box : ^ UI_Box ) -> UI_Signal { | ||||
| 	return {} | ||||
| } | ||||
|  | ||||
| ui_button :: proc( label : string ) -> UI_Signal { | ||||
| 	button_flags : UI_BoxFlags = | ||||
| 		UI_BoxFlags_Clickable & { | ||||
| 			.Draw_Border, | ||||
| 			.Draw_Text, | ||||
| 			.Draw_Background, | ||||
| 			.Focus_Hot, | ||||
| 			.Focus_Active, | ||||
| 		} | ||||
| 	box    := ui_box_make( button_flags, label ) | ||||
| 	signal := ui_signal_from_box( box ) | ||||
| 	return signal | ||||
| } | ||||
|  | ||||
| ui_spacer :: proc ( label : string = UI_NullLabel ) -> UI_Signal { | ||||
| 	box    := ui_box_make( UI_BoxFlags_Null, label ) | ||||
| 	signal := ui_signal_from_box( box ) | ||||
| 	return signal | ||||
| } | ||||
							
								
								
									
										172
									
								
								code/__Imgui_raddbg/ui_box.odin
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										172
									
								
								code/__Imgui_raddbg/ui_box.odin
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,172 @@ | ||||
| package wip | ||||
|  | ||||
| UI_BoxFlag :: enum u64 { | ||||
| 	// Note(rjf) : Interaction | ||||
| 	Mouse_Clickable, | ||||
| 	Keyboard_Clickable, | ||||
| 	Click_To_Focus, | ||||
| 	Scroll, | ||||
| 	View_Scroll_X, | ||||
| 	View_Scroll_Y, | ||||
| 	View_Clamp_X, | ||||
| 	View_Clamp_Y, | ||||
| 	Focus_Active, | ||||
| 	Focus_Active_Disabled, | ||||
| 	Focus_Hot, | ||||
| 	Focus_Hot_Disabled, | ||||
| 	Default_Focus_Nav_X, | ||||
| 	Default_Focus_Nav_Y, | ||||
| 	Default_Focus_Edit, | ||||
| 	Focus_Nav_Skip, | ||||
| 	Disabled, | ||||
|  | ||||
| 	// Note(rjf) : Layout | ||||
| 	Floating_X, | ||||
| 	Floating_Y, | ||||
| 	Fixed_Width, | ||||
| 	Fixed_Height, | ||||
| 	Allow_Overflow_X, | ||||
| 	Allow_Overflow_Y, | ||||
| 	Skip_View_Off_X, | ||||
| 	Skip_View_Off_Y, | ||||
|  | ||||
| 	// Note(rjf) : Appearance / Animation | ||||
| 	Draw_Drop_Shadow, | ||||
| 	Draw_Background_Blur, | ||||
| 	Draw_Background, | ||||
| 	Draw_Border, | ||||
| 	Draw_Side_Top, | ||||
| 	Draw_Side_Bottom, | ||||
| 	Draw_Side_Left, | ||||
| 	Draw_Side_Right, | ||||
| 	Draw_Text, | ||||
| 	Draw_Text_Fastpath_Codepoint, | ||||
| 	Draw_Hot_Effects, | ||||
| 	Draw_Overlay, | ||||
| 	Draw_Bucket, | ||||
| 	Clip, | ||||
| 	Animate_Pos_X, | ||||
| 	Animate_Pos_Y, | ||||
| 	Disable_Text_Trunc, | ||||
| 	Disable_ID_String, | ||||
| 	Disable_Focus_Viz, | ||||
| 	Require_Focus_Background, | ||||
| 	Has_Display_String, | ||||
| 	Has_Fuzzy_Match_Ranges, | ||||
| 	Round_Children_By_Parent, | ||||
|  | ||||
| 	Count, | ||||
| } | ||||
| UI_BoxFlags :: bit_set[UI_BoxFlag; u64] | ||||
|  | ||||
| UI_BoxFlags_Null      :: UI_BoxFlags {} | ||||
| UI_BoxFlags_Clickable :: UI_BoxFlags { .Mouse_Clickable, .Keyboard_Clickable } | ||||
|  | ||||
| UI_NullLabel :: "" | ||||
|  | ||||
| UI_BoxCustomDrawProc :: #type proc( box : ^ UI_Box, user_data : rawptr ) | ||||
|  | ||||
| UI_BoxCustomDraw :: struct { | ||||
| 	callback : UI_BoxCustomDrawProc, | ||||
| 	data     : rawptr, | ||||
| } | ||||
|  | ||||
| UI_BoxRec :: struct { | ||||
| 	next       : ^ UI_BoxNode, | ||||
| 	push_count : i32, | ||||
| 	pop_count  : i32, | ||||
| } | ||||
|  | ||||
| UI_BoxNode :: struct { | ||||
| 	next : ^ UI_BoxNode, | ||||
| 	box  : ^ UI_Box, | ||||
| } | ||||
|  | ||||
| UI_BoxList :: struct { | ||||
| 	first : UI_BoxNode, | ||||
| 	last  : UI_BoxNode, | ||||
| 	count : u64, | ||||
| } | ||||
|  | ||||
| UI_BoxHashSlot :: struct { | ||||
| 	first, last : ^ UI_Box | ||||
| } | ||||
|  | ||||
| // Note(Ed) : This is called UI_Widget in the substack series, its called box in raddbg | ||||
| // This eventually gets renamed by part 4 of the series to UI_Box. | ||||
| // However, its essentially a UI_Node or UI_BaselineEntity, etc. | ||||
| // Think of godot's Control nodes I guess. | ||||
| // TODO(Ed) : We dumped all the fields present within raddbg, review which ones are actually needed. | ||||
| UI_Box :: struct { | ||||
| 	// Note(rjf) : persistent links | ||||
| 	hash : struct { | ||||
| 		next, prev : ^ UI_Box, | ||||
| 	}, | ||||
|  | ||||
| 	// Note(rjf) : Per-build links & data | ||||
| 	// TODO(ED) : Put this in its own struct? | ||||
| 	first, last, prev, next : ^ UI_Box, | ||||
| 	num_children : i32, | ||||
|  | ||||
| 	// Note(rjf) : Key + generation info | ||||
| 	// TODO(ED) : Put this in its own struct? | ||||
| 	key                      : UI_Key, | ||||
| 	last_frame_touched_index : u64, | ||||
|  | ||||
| 	// Note(rjf) : Per-frame info provided by builders | ||||
| 	// TODO(ED) : Put this in its own struct? | ||||
| 	flags              : UI_BoxFlags, | ||||
| 	display_str        : string, // raddbg: string | ||||
| 	semantic_size      : [Axis2.Count]UI_Size, | ||||
| 	text_align         : UI_TextAlign, | ||||
| 	fixed_pos          : Vec2, | ||||
| 	fixed_size         : Vec2, | ||||
| 	pref_size          : [Axis2.Count]UI_Size, | ||||
| 	child_layout_axis  : Axis2, | ||||
| 	hover_cursor       : OS_Cursor, | ||||
| 	fastpath_codepoint : u32, | ||||
| 	draw_bucket        : DrawBucket, // TODO(Ed): Translate to equivalent in raylib if necessary | ||||
| 	custom_draw        : UI_BoxCustomDraw, | ||||
| 	bg_color           : Color, | ||||
| 	text_color         : Color, | ||||
| 	border_color       : Color, | ||||
| 	overlay_color      : Color, | ||||
| 	font               : FontID, | ||||
| 	font_size          : f32, | ||||
| 	corner_radii       : [Corner.Count]f32, | ||||
| 	blur_size          : f32, // TODO(Ed) : You would need to run a custom shader with raylib or have your own rendering backend for this. | ||||
| 	transparency       : f32, | ||||
| 	squish             : f32, | ||||
| 	text_padding       : f32, | ||||
|  | ||||
| 	// Note(rjf) : Per-frame artifacts by builders | ||||
| 	// TODO(ED) : Put this in its own struct? | ||||
| 	display_string_runs : DrawFancyRunList, // TODO(Ed) : Translate to equivalent in raylib if necessary | ||||
| 	rect                : Range2, | ||||
| 	fixed_pos_animated  : Vec2, | ||||
| 	pos_delta           : Vec2, | ||||
| 	fuzzy_match_range   : FuzzyMatchRangeList, // TODO(Ed) : I'm not sure this is needed | ||||
|  | ||||
| 	// Note(rjf) : Computed every frame | ||||
| 	// TODO(ED) : Put this in its own struct? | ||||
| 	computed_rel_pos : Vec2,  // TODO(Ed) : Raddbg doesn't have these, check what they became or if needed | ||||
| 	computed_size    : Vec2, | ||||
|  | ||||
| 	// Note(rjf) : Persistent data | ||||
| 	// TODO(ED) : Put this in its own struct? | ||||
| 	first_touched_build_id     : u64, | ||||
| 	last_touched_build_id      : u64, | ||||
| 	hot_time                   : f32, | ||||
| 	active_time                : f32, | ||||
| 	disabled_time              : f32, | ||||
| 	focus_hot_time             : f32, | ||||
| 	focus_active_time          : f32, | ||||
| 	focus_active_disabled_time : f32, | ||||
| 	view_off                   : Vec2, | ||||
| 	view_off_target            : Vec2, | ||||
| 	view_bounds                : Vec2, | ||||
| 	default_nav_focus_hot_key         : UI_Key, | ||||
| 	default_nav_focus_active_key      : UI_Key, | ||||
| 	default_nav_focus_next_hot_key    : UI_Key, | ||||
| 	default_nav_focus_next_active_key : UI_Key, | ||||
| } | ||||
							
								
								
									
										76
									
								
								code/__Imgui_raddbg/ui_state.odin
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								code/__Imgui_raddbg/ui_state.odin
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,76 @@ | ||||
| package wip | ||||
|  | ||||
| import "core:os" | ||||
|  | ||||
| // TODO(Ed) : As with UI_Box, not all of this will be implemented at once, | ||||
| // we'll need to review this setup for our use case, we will have UI persistent of | ||||
| // a workspace (global state UI), and one for the workspace itself. | ||||
| // The UI state use in raddbg seems to be tied to an OS window and has realted things to it. | ||||
| // You may need to lift the nav actions outside of the UI_State of a workspace, etc... | ||||
| UI_State :: struct { | ||||
| 	arena : ^ Arena, | ||||
|  | ||||
| 	build_arenas : [2] ^ Arena, | ||||
| 	build_id     : u64, | ||||
|  | ||||
| 	// Note(rjf) : Box cache | ||||
| 	// TODO(ED) : Put this in its own struct? | ||||
| 	first_free_box : UI_Box, | ||||
| 	box_table_size : u64, | ||||
| 	box_table      : ^ UI_BoxHashSlot,  // TODO(Ed) : Can the cache use HashTable? | ||||
|  | ||||
| 	// Note(rjf) : Build phase output | ||||
| 	// TODO(ED) : Put this in its own struct? | ||||
| 	root                        : ^ UI_Box, | ||||
| 	tooltip_root                : ^ UI_Box, | ||||
| 	ctx_menu_root               : ^ UI_Box, | ||||
| 	default_nav_root_key        : UI_Key, | ||||
| 	build_box_count             : u64, | ||||
| 	last_build_box_count        : u64, | ||||
| 	ctx_menu_touched_this_frame : b32, | ||||
|  | ||||
| 	// Note(rjf) : Build parameters | ||||
| 	// icon_info  : UI_IconInfo | ||||
| 	// window    : os.Handle | ||||
| 	// events    : OS_EventList | ||||
| 	nav_actions           : UI_NavActionList, | ||||
| 	// TODO(Ed) : Do we want to keep tracvk of the cursor pos separately | ||||
| 	// incase we do some sequence for tutorials? | ||||
| 	mouse                 : Vec2, | ||||
| 	animation_delta       : f32, | ||||
| 	external_focus_commit : b32, | ||||
|  | ||||
| 	// Note(rjf) : User Interaction State | ||||
| 	// TODO(ED) : Put this in its own struct? | ||||
| 	hot_box_key              : UI_Key, | ||||
| 	active_box_key           : [Side.Count] UI_Key, | ||||
| 	clipboard_copy_key       : UI_Key, | ||||
| 	time_since_last_click    : [Side.Count] f32, | ||||
| 	last_click_key           : [Side.Count] UI_Key, | ||||
| 	drag_start_mouse         : Vec2, | ||||
| 	drag_state_arena         : ^ Arena, | ||||
| 	drag_state_data          : string, | ||||
| 	string_hover_arena       : ^ Arena, | ||||
| 	string_hover_string      : string, | ||||
| 	string_hover_fancy_runs  : DrawFancyRunList, | ||||
| 	string_hover_begin_us    : u64, | ||||
| 	string_hover_build_index : u64, | ||||
| 	last_time_mouse_moved_us : u64, | ||||
|  | ||||
| 	// Note(rjf) : Tooltip State | ||||
| 	// TODO(ED) : Put this in its own struct? | ||||
| 	tool_tip_open_time : f32, | ||||
| 	tool_tip_open      : b32, | ||||
|  | ||||
| 	// Note(rjf) : Context menu state | ||||
| 	// TODO(ED) : Put this in its own struct? | ||||
| 	ctx_menu_anchor_key          : UI_Key, | ||||
| 	next_ctx_menu_anchor_key     : UI_Key, | ||||
| 	ctx_menu_anchor_box_last_pos : Vec2, | ||||
| 	cxt_menu_anchor_off          : Vec2, | ||||
| 	ctx_menu_open                : b32, | ||||
| 	next_ctx_menu_open           : b32, | ||||
| 	ctx_menu_open_time           : f32, | ||||
| 	ctx_menu_key                 : UI_Key, | ||||
| 	ctx_menu_changed             : b32, | ||||
| } | ||||
| @@ -1,6 +1,7 @@ | ||||
| package sectr | ||||
|  | ||||
| import    "base:runtime" | ||||
| import  c "core:c/libc" | ||||
| import    "core:dynlib" | ||||
| import    "core:fmt" | ||||
| import    "core:mem" | ||||
| @@ -71,6 +72,8 @@ startup :: proc( live_mem : virtual.Arena, snapshot_mem : []u8, host_logger : ^ | ||||
| 	input      = & input_data[1] | ||||
| 	input_prev = & input_data[0] | ||||
|  | ||||
| 	// rl.Odin_SetMalloc( RL_MALLOC ) | ||||
|  | ||||
| 	rl.SetConfigFlags( { rl.ConfigFlag.WINDOW_RESIZABLE /*, rl.ConfigFlag.WINDOW_TOPMOST*/ } ) | ||||
|  | ||||
| 	// Rough setup of window with rl stuff | ||||
| @@ -145,6 +148,8 @@ startup :: proc( live_mem : virtual.Arena, snapshot_mem : []u8, host_logger : ^ | ||||
|  | ||||
| 			frame_2.color = Color_BG_TextBox_Green | ||||
| 			box_set_size( & frame_2, { 60, 100 } * CM_Per_Point ) | ||||
|  | ||||
|  | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|   | ||||
							
								
								
									
										5
									
								
								code/app_startup.odin
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								code/app_startup.odin
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| package sectr | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| @@ -132,12 +132,24 @@ AppWindow :: struct { | ||||
| 	ppcm      : f32,      // Dots per centimetre | ||||
| } | ||||
|  | ||||
| // PMDB | ||||
| CodeBase :: struct { | ||||
| 	placeholder : int, | ||||
| } | ||||
|  | ||||
| ProjectConfig :: struct { | ||||
| 	placeholder : int, | ||||
| } | ||||
|  | ||||
| Project :: struct { | ||||
| 	path : string, | ||||
| 	name : string, | ||||
|  | ||||
| 	config   : ProjectConfig, | ||||
| 	codebase : CodeBase, | ||||
|  | ||||
| 	// TODO(Ed) : Support multiple workspaces | ||||
| 	workspace : Workspace | ||||
| 	workspace : Workspace, | ||||
| } | ||||
|  | ||||
| Workspace :: struct { | ||||
| @@ -146,6 +158,9 @@ Workspace :: struct { | ||||
| 	cam     : Camera, | ||||
| 	frame_1 : Box2, | ||||
| 	frame_2 : Box2, | ||||
|  | ||||
| 	// TODO(Ed) : The workspace is mainly a 'UI' conceptually... | ||||
| 	ui : UI_State, | ||||
| } | ||||
|  | ||||
| DebugData :: struct { | ||||
|   | ||||
| @@ -9,7 +9,7 @@ import "core:os" | ||||
| import rl "vendor:raylib" | ||||
|  | ||||
| Font_Arena_Size      :: 32 * Megabyte | ||||
| Font_Largest_Px_Size :: 96 | ||||
| Font_Largest_Px_Size :: 32 | ||||
|  | ||||
| // Font_Default :: "" | ||||
| Font_Default            :: 0 | ||||
| @@ -56,6 +56,7 @@ FontProviderData :: struct { | ||||
|  | ||||
| 	//TODO(Ed) : There is an issue with hot-reload and map allocations that I can't figure out right now.. | ||||
| 	// font_cache : ^ map [FontID](FontDef), | ||||
| 	// font_cache : HashTable(FontDef), | ||||
| 	font_cache : [10] FontDef, | ||||
| 	open_id    : i32 | ||||
| } | ||||
|   | ||||
							
								
								
									
										101
									
								
								code/grime.odin
									
									
									
									
									
								
							
							
						
						
									
										101
									
								
								code/grime.odin
									
									
									
									
									
								
							| @@ -3,8 +3,11 @@ package sectr | ||||
| // At least its less than C/C++ ... | ||||
|  | ||||
| import "base:builtin" | ||||
| import "base:runtime" | ||||
| import c "core:c/libc" | ||||
| import "core:mem" | ||||
| import "core:mem/virtual" | ||||
| import "core:os" | ||||
| import "core:path/filepath" | ||||
|  | ||||
| Byte     :: 1 | ||||
| @@ -49,3 +52,101 @@ get_bounds :: proc { | ||||
| 	box_get_bounds, | ||||
| 	view_get_bounds, | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| // TODO(Ed) : This is extremely jank, Raylib requires a 'heap' allocator with the way it works. | ||||
| // We do not have persistent segmented in such a way for this. Eventually we might just want to segment vmem and just shove a heap allocator on a segment of it. | ||||
|  | ||||
| when false { | ||||
| RL_MALLOC :: proc "c" ( size : c.size_t ) -> rawptr | ||||
| { | ||||
| 	allocator : Allocator | ||||
| 	when Use_TrackingAllocator { | ||||
| 		allocator = Allocator { | ||||
| 			data      = & memory.persistent.tracker, | ||||
| 			procedure = mem.tracking_allocator_proc, | ||||
| 		} | ||||
| 	} | ||||
| 	else { | ||||
| 		allocator = Allocator { | ||||
| 			data      = & memory.persistent, | ||||
| 			procedure = mem.arena_allocator_proc, | ||||
| 		} | ||||
| 	} | ||||
| 	result, error_code := allocator.procedure( allocator.data, mem.Allocator_Mode.Alloc_Non_Zeroed, cast(int) size, mem.DEFAULT_ALIGNMENT, nil, 0, auto_cast {} ) | ||||
| 	if error_code != AllocatorError.None { | ||||
| 		runtime.debug_trap() | ||||
| 		os.exit( -1 ) | ||||
| 	} | ||||
| 	return raw_data(result) | ||||
| } | ||||
|  | ||||
| RL_CALLOC :: proc "c" ( count : c.size_t, size : c.size_t ) -> rawptr | ||||
| { | ||||
| 	allocator : Allocator | ||||
| 	when Use_TrackingAllocator { | ||||
| 		allocator = Allocator { | ||||
| 			data      = & memory.persistent.tracker, | ||||
| 			procedure = mem.tracking_allocator_proc, | ||||
| 		} | ||||
| 	} | ||||
| 	else { | ||||
| 		allocator = Allocator { | ||||
| 			data      = & memory.persistent, | ||||
| 			procedure = mem.arena_allocator_proc, | ||||
| 		} | ||||
| 	} | ||||
| 	result, error_code := allocator.procedure( allocator.data, mem.Allocator_Mode.Alloc, cast(int) size, mem.DEFAULT_ALIGNMENT, nil, 0, auto_cast {} ) | ||||
| 	if error_code != AllocatorError.None { | ||||
| 		runtime.debug_trap() | ||||
| 		os.exit( -1 ) | ||||
| 	} | ||||
| 	return raw_data(result) | ||||
| } | ||||
|  | ||||
| RL_REALLOC :: proc "c" ( block : rawptr, size : c.size_t ) -> rawptr | ||||
| { | ||||
| 	allocator : Allocator | ||||
| 	when Use_TrackingAllocator { | ||||
| 		allocator = Allocator { | ||||
| 			data      = & memory.persistent.tracker, | ||||
| 			procedure = mem.tracking_allocator_proc, | ||||
| 		} | ||||
| 	} | ||||
| 	else { | ||||
| 		allocator = Allocator { | ||||
| 			data      = & memory.persistent, | ||||
| 			procedure = mem.arena_allocator_proc, | ||||
| 		} | ||||
| 	} | ||||
| 	result, error_code := allocator.procedure( allocator.data, mem.Allocator_Mode.Resize_Non_Zeroed, cast(int) size, mem.DEFAULT_ALIGNMENT, block, 0, auto_cast {} ) | ||||
| 	if error_code != AllocatorError.None { | ||||
| 		runtime.debug_trap() | ||||
| 		os.exit( -1 ) | ||||
| 	} | ||||
| 	return raw_data(result) | ||||
| } | ||||
|  | ||||
| RL_FREE :: proc "c" ( block : rawptr ) | ||||
| { | ||||
| 	allocator : Allocator | ||||
| 	when Use_TrackingAllocator { | ||||
| 		allocator = Allocator { | ||||
| 			data      = & memory.persistent.tracker, | ||||
| 			procedure = mem.tracking_allocator_proc, | ||||
| 		} | ||||
| 	} | ||||
| 	else { | ||||
| 		allocator = Allocator { | ||||
| 			data      = & memory.persistent, | ||||
| 			procedure = mem.arena_allocator_proc, | ||||
| 		} | ||||
| 	} | ||||
| 	result, error_code := allocator.procedure( allocator.data, mem.Allocator_Mode.Free, 0, 0, block, 0, auto_cast {} ) | ||||
| 	if error_code != AllocatorError.None { | ||||
| 		runtime.debug_trap() | ||||
| 		os.exit( -1 ) | ||||
| 	} | ||||
| } | ||||
| } | ||||
| @@ -3,6 +3,8 @@ | ||||
| // with hot-reloads... | ||||
| package sectr | ||||
|  | ||||
| // Note(Ed) : See core:hash for hasing procs. | ||||
|  | ||||
| // This might be problematic... | ||||
| HT_MapProc    :: #type proc( $ Type : typeid, key : u64, value :   Type ) | ||||
| HT_MapMutProc :: #type proc( $ Type : typeid, key : u64, value : ^ Type ) | ||||
|   | ||||
| @@ -129,3 +129,14 @@ arena_init_static :: proc(arena: ^virtual.Arena, base_address : rawptr, | ||||
|  | ||||
| // END WINDOWS CHECK WRAP | ||||
| } | ||||
| else | ||||
| { | ||||
| 	// Fallback to regular init_static impl for other platforms for now. | ||||
|  | ||||
| 	arena_init_static :: proc(arena: ^virtual.Arena, base_address : rawptr, | ||||
| 		reserved    : uint = virtual.DEFAULT_ARENA_STATIC_RESERVE_SIZE, | ||||
| 		commit_size : uint = virtual.DEFAULT_ARENA_STATIC_COMMIT_SIZE | ||||
| 	) -> (err: virtual.Allocator_Error) { | ||||
| 		return virtual.arena_init_static( arena, reserved, commit_size ) | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -2,6 +2,8 @@ package sectr | ||||
|  | ||||
| import rl "vendor:raylib" | ||||
|  | ||||
| // TODO(Ed) : Do we want to have distinct types for cm/pixels/points ? This will make mistakes with unit conversion happen less. | ||||
|  | ||||
| // The points to pixels and pixels to points are our only reference to accurately converting | ||||
| // an object from world space to screen-space. | ||||
| // This prototype engine will have all its spacial unit base for distances in centimetres. | ||||
| @@ -16,7 +18,7 @@ DPT_PPCM      :: cast(f32) 96.0 * Inches_To_CM // 243.84 pixels per cm | ||||
| when ODIN_OS == OS_Type.Windows { | ||||
| 	op_default_dpcm :: 72.0 * Inches_To_CM | ||||
| 	os_default_ppcm :: 96.0 * Inches_To_CM | ||||
| 	// 1 inch = 2.54 cm, 96 inch * 2.54 = 243.84 DPC | ||||
| 	// 1 inch = 2.54 cm, 96 inch * 2.54 = 243.84 DPCM | ||||
| } | ||||
|  | ||||
| cm_to_pixels :: proc { | ||||
|   | ||||
| @@ -19,7 +19,7 @@ render :: proc() | ||||
| 	rl.BeginDrawing() | ||||
| 	rl.ClearBackground( Color_BG ) | ||||
| 	render_mode_2d() | ||||
| 	// Render Screenspace | ||||
| 	//region Render Screenspace | ||||
| 	{ | ||||
| 		fps_msg       := fmt.tprint( "FPS:", rl.GetFPS() ) | ||||
| 		fps_msg_width := measure_text_size( fps_msg, default_font, 16.0, 0.0 ).x | ||||
| @@ -68,6 +68,7 @@ render :: proc() | ||||
|  | ||||
| 		debug.draw_debug_text_y = 50 | ||||
| 	} | ||||
| 	//endregion Render Screenspace | ||||
| 	rl.EndDrawing() | ||||
| } | ||||
|  | ||||
| @@ -79,27 +80,11 @@ render_mode_2d :: proc() | ||||
|  | ||||
| 	rl.BeginMode2D( project.workspace.cam ) | ||||
|  | ||||
| 	// debug.frame_1_on_top = true | ||||
| 	//region Imgui Render | ||||
| 	{ | ||||
|  | ||||
| 	boxes : [2]^Box2 | ||||
| 	if debug.frame_1_on_top { | ||||
| 		boxes = { & project.workspace.frame_2, & project.workspace.frame_1 } | ||||
| 	} | ||||
| 	else { | ||||
| 		boxes = { & project.workspace.frame_1, & project.workspace.frame_2 } | ||||
| 	} | ||||
|  | ||||
| 	for box in boxes { | ||||
| 		screen_pos := world_to_screen_no_zoom(box.position) - vec2_cm_to_pixels( Vec2(box.extent) ) | ||||
| 		size       := vec2_cm_to_pixels( transmute(Vec2) box.extent * 2.0 ) | ||||
|  | ||||
| 		rect : rl.Rectangle | ||||
| 		rect.x      = screen_pos.x | ||||
| 		rect.y      = screen_pos.y | ||||
| 		rect.width  = size.x | ||||
| 		rect.height = size.y | ||||
| 		rl.DrawRectangleRec( rect, box.color ) | ||||
| 	} | ||||
| 	//endregion Imgui Render | ||||
|  | ||||
| 	debug_draw_text_world( "This is text in world space", { 0, 0 }, 16.0  ) | ||||
|  | ||||
|   | ||||
| @@ -86,7 +86,7 @@ update :: proc( delta_time : f64 ) -> b32 | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Input Replay | ||||
| 	//region Input Replay | ||||
| 	{ | ||||
| 		if debug_actions.record_replay { #partial switch replay.mode | ||||
| 		{ | ||||
| @@ -129,27 +129,28 @@ update :: proc( delta_time : f64 ) -> b32 | ||||
| 			play_input( replay.active_file, input ) | ||||
| 		} | ||||
| 	} | ||||
| 	//endregion Input Replay | ||||
|  | ||||
| 	if debug_actions.show_mouse_pos { | ||||
| 		debug.mouse_vis = !debug.mouse_vis | ||||
| 	} | ||||
|  | ||||
| 	// Camera Manual Nav | ||||
| 	//region Camera Manual Nav | ||||
| 	{ | ||||
| 		cam := & project.workspace.cam | ||||
|  | ||||
| 		digital_move_speed : f32 = 200.0 | ||||
| 		zoom_sensitivity   : f32 = 0.2 // Digital | ||||
| 		// zoom_sensitivity   : f32 = 2.0  // Smooth | ||||
| 		// zoom_sensitivity   : f32 = 0.2 // Digital | ||||
| 		zoom_sensitivity   : f32 = 4.0  // Smooth | ||||
|  | ||||
| 		if debug.zoom_target == 0.0 { | ||||
| 			debug.zoom_target = cam.zoom | ||||
| 		} | ||||
|  | ||||
|     // Adjust zoom_target based on input, not the actual zoom | ||||
|     zoom_delta        := input.mouse.vertical_wheel * zoom_sensitivity | ||||
|     debug.zoom_target *= 1 + zoom_delta //* f32(delta_time) | ||||
|     debug.zoom_target  = clamp(debug.zoom_target, 0.25, 10.0) | ||||
| 		// Adjust zoom_target based on input, not the actual zoom | ||||
| 		zoom_delta        := input.mouse.vertical_wheel * zoom_sensitivity | ||||
| 		debug.zoom_target *= 1 + zoom_delta * f32(delta_time) | ||||
| 		debug.zoom_target  = clamp(debug.zoom_target, 0.25, 10.0) | ||||
|  | ||||
| 		// Linearly interpolate cam.zoom towards zoom_target | ||||
| 		lerp_factor := cast(f32) 4.0 // Adjust this value to control the interpolation speed | ||||
| @@ -171,32 +172,14 @@ update :: proc( delta_time : f64 ) -> b32 | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	//endregion | ||||
|  | ||||
| 	boxes : [2]^Box2 | ||||
| 	boxes = { & project.workspace.frame_1, & project.workspace.frame_2 } | ||||
| 	if debug.frame_1_on_top { | ||||
| 		boxes = { & project.workspace.frame_2, & project.workspace.frame_1 } | ||||
| 	} | ||||
| 	else { | ||||
| 		boxes = { & project.workspace.frame_1, & project.workspace.frame_2 } | ||||
| 	} | ||||
|  | ||||
| 	if debug_actions.mouse_select | ||||
| 	//region Imgui Tick | ||||
| 	{ | ||||
| 		for box in boxes | ||||
| 		{ | ||||
| 			cursor_pos := screen_to_world( input.mouse.pos ) | ||||
| 			if box_is_within( box, cursor_pos ) | ||||
| 			{ | ||||
| 				if box == & project.workspace.frame_1 { | ||||
| 					debug.frame_1_on_top = true | ||||
| 				} | ||||
| 				else { | ||||
| 					debug.frame_1_on_top = false | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		// Layout  | ||||
|  | ||||
| 	} | ||||
| 	// endregion | ||||
|  | ||||
| 	debug.last_mouse_pos = input.mouse.pos | ||||
|  | ||||
|   | ||||
							
								
								
									
										404
									
								
								code/ui.odin
									
									
									
									
									
								
							
							
						
						
									
										404
									
								
								code/ui.odin
									
									
									
									
									
								
							| @@ -1,272 +1,208 @@ | ||||
| package sectr | ||||
|  | ||||
| // Based off Ryan Fleury's UI Series & Epic's RAD Debugger which directly implements a version of it. | ||||
| // You will see Note(rjf) these are comments directly from the RAD Debugger codebase by Fleury. | ||||
| // TODO(Ed) If I can, I would like this to be its own package, but the nature of packages in odin may make this difficult. | ||||
|  | ||||
| // TODO(Ed) : This is in Raddbg base_types.h, consider moving outside of UI. | ||||
| Axis2 :: enum { | ||||
| 	Invalid =  -1, | ||||
| 	X, | ||||
| 	Y, | ||||
| Axis2 :: enum i32 { | ||||
| 	Invalid = -1, | ||||
| 	X       = 0, | ||||
| 	Y       = 1, | ||||
| 	Count, | ||||
| } | ||||
|  | ||||
| UI_FocusKind :: enum u32 { | ||||
| 	Null, | ||||
| 	Off, | ||||
| 	On, | ||||
| 	Root, | ||||
| Corner :: enum i32 { | ||||
| 	Invalid = -1, | ||||
| 	_00, | ||||
| 	_01, | ||||
| 	_10, | ||||
| 	_11, | ||||
| 	TopLeft     = _00, | ||||
| 	TopRight    = _01, | ||||
| 	BottomLeft  = _10, | ||||
| 	BottomRight = _11, | ||||
| 	Count = 4, | ||||
| } | ||||
|  | ||||
| Range2 :: struct #raw_union{ | ||||
| 	using _ : struct { | ||||
| 		min, max : Vec2 | ||||
| 	}, | ||||
| 	using _ : struct { | ||||
| 		p0, p1 : Vec2 | ||||
| 	}, | ||||
| 	using _ : struct { | ||||
| 		x0, y0 : f32, | ||||
| 		x1, y1 : f32, | ||||
| 	}, | ||||
| } | ||||
|  | ||||
| Rect :: struct { | ||||
| 	top_left, bottom_right : Vec2 | ||||
| } | ||||
|  | ||||
| Side :: enum i32 { | ||||
| 	Invalid = -1, | ||||
| 	Min     = 0, | ||||
| 	Max     = 1, | ||||
| 	Count | ||||
| } | ||||
|  | ||||
| // Side2 :: enum u32 { | ||||
| // 	Top, | ||||
| // 	Bottom, | ||||
| // 	Left, | ||||
| // 	Right, | ||||
| // 	Count, | ||||
| // } | ||||
|  | ||||
| UI_AnchorPresets :: enum u32 { | ||||
| 	Top_Left, | ||||
| 	Top_Right, | ||||
| 	Bottom_Right, | ||||
| 	Bottom_Left, | ||||
| 	Center_Left, | ||||
| 	Center_Top, | ||||
| 	Center_Right, | ||||
| 	Center_Bottom, | ||||
| 	Center, | ||||
| 	Left_Wide, | ||||
| 	Top_Wide, | ||||
| 	Right_Wide, | ||||
| 	Bottom_Wide, | ||||
| 	VCenter_Wide, | ||||
| 	HCenter_Wide, | ||||
| 	Full, | ||||
| 	Count, | ||||
| } | ||||
|  | ||||
| UI_IconKind :: enum u32 { | ||||
| 	Null, | ||||
| 	Arrow_Up, | ||||
| 	Arrow_Left, | ||||
| 	Arrow_Right, | ||||
| 	Arrow_Down, | ||||
| 	Caret_Up, | ||||
| 	Caret_Left, | ||||
| 	Caret_Right, | ||||
| 	Caret_Down, | ||||
| 	Check_Hollow, | ||||
| 	Check_Filled, | ||||
| 	Count, | ||||
| } | ||||
|  | ||||
| UI_IconInfo :: struct { | ||||
| 	placehodler : int | ||||
| } | ||||
|  | ||||
| UI_NavDeltaUnit :: enum u32 { | ||||
| 	Element, | ||||
| 	Chunk, | ||||
| 	Whole, | ||||
| 	End_Point, | ||||
| 	Count, | ||||
| } | ||||
|  | ||||
| UI_NavActionFlag :: enum u32 { | ||||
| 	Keep_Mark, | ||||
| 	Delete, | ||||
| 	Copy, | ||||
| 	Paste, | ||||
| 	Zero_Delta_On_Select, | ||||
| 	Pick_Select_Side, | ||||
| 	Can_At_Line, | ||||
| 	Explicit_Directional, | ||||
| 	Replace_And_Commit, | ||||
| } | ||||
| UI_NavActionFlags :: bit_set[UI_NavActionFlag; u32] | ||||
|  | ||||
| UI_NavAction :: struct { | ||||
| 	flags      : UI_NavActionFlags, | ||||
| 	delta      : Vec2i, | ||||
| 	delta_unit : UI_NavDeltaUnit, | ||||
| 	insertion  : string, | ||||
| } | ||||
|  | ||||
| UI_SizeKind :: enum u32 { | ||||
| 	Null, | ||||
| 	Pixels, | ||||
| 	Points, | ||||
| 	TextContent, | ||||
| 	PercentOfParent, | ||||
| 	ChildrenSum, | ||||
| 	Count, | ||||
| } | ||||
|  | ||||
| UI_Size :: struct { | ||||
| 	kind       : UI_SizeKind, | ||||
| 	value      : f32, | ||||
| 	strictness : f32, | ||||
| } | ||||
|  | ||||
| UI_Size2 : struct { | ||||
| 	kind       : [Axis2.Count]UI_SizeKind, | ||||
| 	value      : Vec2, | ||||
| 	strictness : Vec2, | ||||
| } | ||||
|  | ||||
| UI_Layout :: struct { | ||||
| 	placeholder : int | ||||
| } | ||||
|  | ||||
| UI_Key :: struct { | ||||
| 	opaque : [1]u64, | ||||
| } | ||||
|  | ||||
| UI_BoxFlag :: enum u64 { | ||||
| 	// Note(rjf) : Interaction | ||||
| 	Focusable, | ||||
|  | ||||
| 	Mouse_Clickable, | ||||
| 	Keyboard_Clickable, | ||||
| 	Click_To_Focus, | ||||
| 	Scroll, | ||||
| 	View_Scroll_X, | ||||
| 	View_Scroll_Y, | ||||
| 	View_Clamp_X, | ||||
| 	View_Clamp_Y, | ||||
| 	Focus_Active, | ||||
| 	Focus_Active_Disabled, | ||||
| 	Focus_Hot, | ||||
| 	Focus_Hot_Disabled, | ||||
| 	Default_Focus_Nav_X, | ||||
| 	Default_Focus_Nav_Y, | ||||
| 	Default_Focus_Edit, | ||||
| 	Focus_Nav_Skip, | ||||
| 	Disabled, | ||||
|  | ||||
| 	// Note(rjf) : Layout | ||||
| 	Floating_X, | ||||
| 	Floating_Y, | ||||
| 	Fixed_Width, | ||||
| 	Fixed_With, | ||||
| 	Fixed_Height, | ||||
| 	Allow_Overflow_X, | ||||
| 	Allow_Overflow_Y, | ||||
| 	Skip_View_Off_X, | ||||
| 	Skip_View_Off_Y, | ||||
|  | ||||
| 	// Note(rjf) : Appearance / Animation | ||||
| 	Draw_Drop_Shadow, | ||||
| 	Draw_Background_Blur, | ||||
| 	Draw_Background, | ||||
| 	Draw_Border, | ||||
| 	Draw_Side_Top, | ||||
| 	Draw_Side_Bottom, | ||||
| 	Draw_Side_Left, | ||||
| 	Draw_Side_Right, | ||||
| 	Draw_Text, | ||||
| 	Draw_Text_Fastpath_Codepoint, | ||||
| 	Draw_Hot_Effects, | ||||
| 	Draw_Overlay, | ||||
| 	Draw_Bucket, | ||||
| 	Clip, | ||||
| 	Animate_Pos_X, | ||||
| 	Animate_Pos_Y, | ||||
| 	Disable_Text_Trunc, | ||||
| 	Disable_ID_String, | ||||
| 	Disable_Focus_Viz, | ||||
| 	Require_Focus_Background, | ||||
| 	Has_Display_String, | ||||
| 	Has_Fuzzy_Match_Ranges, | ||||
| 	Round_Children_By_Parent, | ||||
| 	Text_Wrap, | ||||
|  | ||||
| 	Count, | ||||
| } | ||||
| UI_BoxFlags :: bit_set[UI_BoxFlag; u64] | ||||
|  | ||||
| UI_BoxFlags_Null      :: UI_BoxFlags {} | ||||
| UI_BoxFlags_Clickable :: UI_BoxFlags { .Mouse_Clickable, .Keyboard_Clickable } | ||||
| // The UI_Box's actual positioning and sizing | ||||
| // There is an excess of rectangles here for debug puproses. | ||||
| UI_Computed :: struct { | ||||
| 	bounds  : Range2, | ||||
| 	border  : Range2, | ||||
| 	margin  : Range2, | ||||
| 	padding : Range2, | ||||
| 	content : Range2, | ||||
| } | ||||
|  | ||||
| UI_NullLabel :: "" | ||||
| UI_LayoutSide :: struct #raw_union { | ||||
| 	using _ :  struct { | ||||
| 		top, bottom : UI_Scalar2, | ||||
| 		left, right : UI_Scalar2, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| UI_Cursor :: struct { | ||||
| 	placeholder : int, | ||||
| } | ||||
|  | ||||
| UI_Key :: distinct u64 | ||||
|  | ||||
| UI_Scalar :: f32 | ||||
|  | ||||
| // TODO(Ed): I'm not sure if Percentage is needed or if this would over complicate things... | ||||
| // UI_Scalar :: struct { | ||||
| // 	VPixels    : f32, | ||||
| // 	Percentage : f32, | ||||
| // } | ||||
|  | ||||
| UI_ScalarConstraint :: struct { | ||||
| 	min, max : UI_Scalar, | ||||
| } | ||||
|  | ||||
| UI_Scalar2 :: [Axis2.Count]UI_Scalar | ||||
|  | ||||
| // Desiered constraints on the UI_Box. | ||||
| UI_Layout :: struct { | ||||
| 	// TODO(Ed) : Make sure this is all we need to represent an anchor. | ||||
| 	anchor : Range2, | ||||
|  | ||||
| 	border_width : UI_Scalar, | ||||
|  | ||||
| 	margins : UI_LayoutSide, | ||||
| 	padding : UI_LayoutSide, | ||||
|  | ||||
| 	corner_radii : [Corner.Count]f32, | ||||
|  | ||||
| 	size : UI_ScalarConstraint, | ||||
| } | ||||
|  | ||||
| UI_Style :: struct { | ||||
| 	bg_color      : Color, | ||||
| 	overlay_color : Color, | ||||
| 	border_color  : Color, | ||||
|  | ||||
| 	// blur_size : f32, | ||||
|  | ||||
| 	font                    : FontID, | ||||
| 	font_size               : f32, | ||||
| 	text_color              : Color, | ||||
| 	text_alignment          : UI_TextAlign, | ||||
| 	// text_wrap_width_pixels  : f32, | ||||
| 	// text_wrap_width_percent : f32, | ||||
|  | ||||
| 	// cursors       : [CursorKind.Count]UI_Cursor, | ||||
| 	// active_cursor : ^UI_Cursor, | ||||
| 	// hover_cursor : ^ UI_Cursor, | ||||
| } | ||||
|  | ||||
| UI_TextAlign :: enum u32 { | ||||
| 	Left, | ||||
| 	Center, | ||||
| 	Right, | ||||
| 	Count | ||||
| } | ||||
|  | ||||
| // Note(Ed) : This is called UI_Widget in the substack series, its called box in raddbg | ||||
| // This eventually gets renamed by part 4 of the series to UI_Box. | ||||
| // However, its essentially a UI_Node or UI_BaselineEntity, etc. | ||||
| // Think of godot's Control nodes I guess. | ||||
| UI_Box :: struct { | ||||
| 	// Note(rjf) : persistent links | ||||
| 	hash : struct { | ||||
| 		next, prev : ^ UI_Box, | ||||
| 	}, | ||||
|  | ||||
| 	// Note(rjf) : Per-build links & data | ||||
| 	first, last, prev, next : ^ UI_Box, | ||||
| 	num_children : i32, | ||||
|  | ||||
| 	// Note(rjf) : Key + generation info | ||||
| 	key                      : UI_Key, | ||||
| 	last_frame_touched_index : u64, | ||||
|  | ||||
| 	// Note(rjf) : Per-frame info provided by builders | ||||
| 	flags : UI_BoxFlags, | ||||
| 	display_str : string, | ||||
| 	semantic_size : [Axis2.Count]UI_Size, | ||||
|  | ||||
| 	key   : UI_Key, | ||||
| 	label : string, | ||||
|  | ||||
| 	// Note(rjf) : Computed every frame | ||||
| 	computed_rel_pos : Vec2, | ||||
| 	computed_size    : Vec2, | ||||
| 	//rect : Rng2F32 | ||||
| 	computed : UI_Computed, | ||||
|  | ||||
| 	// Note(rjf) : Persistent data | ||||
| 	hot    : f32, | ||||
| 	active : f32, | ||||
| 	layout : UI_Layout, | ||||
| 	style  : UI_Style, | ||||
|  | ||||
| 	// bg_color  : Color, | ||||
| 	// txt_color : Color, | ||||
| 	// Persistent Data | ||||
| 	hot_time      : f32, | ||||
| 	active_time   : f32, | ||||
| 	disabled_time : f32, | ||||
| } | ||||
|  | ||||
| UI_Signal :: struct { | ||||
| 	box : UI_Box, | ||||
| 	cursor_pos : Vec2, | ||||
| 	drag_delta : Vec2, | ||||
| 	scroll     : Vec2, | ||||
| 	left_clicked     : b8, | ||||
| 	right_clicked    : b8, | ||||
| 	double_clicked   : b8, | ||||
| 	keyboard_clicked : b8, | ||||
| 	pressed    : b8, | ||||
| 	released   : b8, | ||||
| 	dragging   : b8, | ||||
| 	hovering   : b8, | ||||
| 	mouse_over : b8, | ||||
| 	commit     : b8, | ||||
| UI_State :: struct { | ||||
| 	box_cache : HashTable( UI_Box ), | ||||
|  | ||||
| 	box_tree_dirty : b32, | ||||
| 	root           : ^ UI_Box, | ||||
|  | ||||
| 	hot                : UI_Key, | ||||
| 	active             : UI_Key, | ||||
| 	clipboard_copy_key : UI_Key, | ||||
|  | ||||
| 	drag_start_mouse : Vec2, | ||||
| 	// drag_state_arena : ^ Arena, | ||||
| 	// drag_state data  : string, | ||||
| } | ||||
|  | ||||
| ui_key_null :: proc() -> UI_Key { | ||||
| 	return {} | ||||
| } | ||||
|  | ||||
| ui_key_from_string :: proc( value : string ) -> UI_Key { | ||||
| 	 return {} | ||||
| } | ||||
|  | ||||
| ui_key_match :: proc( a, b : UI_Key ) -> b32 { | ||||
| 	 return false | ||||
| } | ||||
|  | ||||
| ui_box_make :: proc( flags : UI_BoxFlags, label : string ) -> (^ UI_Box) { | ||||
| ui_box_make :: proc( flags : UI_BoxFlags, label : string ) -> (^ UI_Box) | ||||
| { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| ui_box_equip_display_string :: proc( box : ^ UI_Box, display_string : string ) { | ||||
|  | ||||
| } | ||||
|  | ||||
| ui_box_equip_child_layout_axis :: proc( box : ^ UI_Box, axis : Axis2 ) { | ||||
|  | ||||
| } | ||||
|  | ||||
| ui_push_parent :: proc( box : ^ UI_Box ) -> (^ UI_Box) { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| ui_pop_parent :: proc() -> (^ UI_Box) { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| ui_signal_from_box :: proc( box : ^ UI_Box ) -> UI_Signal { | ||||
| 	return {} | ||||
| } | ||||
|  | ||||
| ui_button :: proc( label : string ) -> UI_Signal { | ||||
| 	button_flags : UI_BoxFlags = | ||||
| 		UI_BoxFlags_Clickable & { | ||||
| 			.Draw_Border, | ||||
| 			.Draw_Text, | ||||
| 			.Draw_Background, | ||||
| 			.Focus_Hot, | ||||
| 			.Focus_Active, | ||||
| 		} | ||||
| 	box    := ui_box_make( button_flags, label ) | ||||
| 	signal := ui_signal_from_box( box ) | ||||
| 	return signal | ||||
| } | ||||
|  | ||||
| ui_spacer :: proc ( label : string = UI_NullLabel ) -> UI_Signal { | ||||
| 	box    := ui_box_make( UI_BoxFlags_Null, label ) | ||||
| 	signal := ui_signal_from_box( box ) | ||||
| 	return signal | ||||
| } | ||||
|   | ||||
							
								
								
									
										5
									
								
								code/ui_proto.odin
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								code/ui_proto.odin
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| package sectr | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
		Reference in New Issue
	
	Block a user