Support for rounded rectangles & borders (not the best implementation...)
This commit is contained in:
		| @@ -182,7 +182,7 @@ ui_screen_settings_menu :: proc( captures : rawptr = nil ) -> ( should_raise : b | ||||
| 					using title | ||||
| 					layout.anchor.ratio.x = 1.0 | ||||
| 					layout.margins        = { 0, 0, 15, 0} | ||||
| 					layout.font_size      = 16 | ||||
| 					layout.font_size      = 14 | ||||
| 				} | ||||
|  | ||||
| 				scope(theme_window_bar_btn) | ||||
| @@ -200,6 +200,7 @@ ui_screen_settings_menu :: proc( captures : rawptr = nil ) -> ( should_raise : b | ||||
| 					text = str_intern("close") | ||||
| 					if close_btn.hot     do style.bg_color =  app_color.window_btn_close_bg_hot | ||||
| 					if close_btn.pressed do settings_menu.is_open = false | ||||
| 					style.corner_radii = { 0, 0, 0, 0 } | ||||
| 				} | ||||
| 			} | ||||
| 			if frame_bar.active { | ||||
| @@ -208,13 +209,15 @@ ui_screen_settings_menu :: proc( captures : rawptr = nil ) -> ( should_raise : b | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if ui_drop_down( & cfg_drop_down, "settings_menu.config", str_intern("App Config"), vb_compute_layout = true).is_open | ||||
| 		app_config := ui_drop_down( & cfg_drop_down, "settings_menu.config", str_intern("App Config"), vb_compute_layout = true) | ||||
| 		app_config.title.layout.font_size = 12 | ||||
| 		if app_config.is_open | ||||
| 		{ | ||||
| 			Engien_Refresh_Hz: | ||||
| 			{ | ||||
| 				scope(theme_table_row(is_even = false)) | ||||
| 				hb := ui_hbox(.Left_To_Right, "settings_menu.engine_refresh_hz.hb"); { using hb | ||||
| 					layout.size.min = {0, 30} | ||||
| 					layout.size.min = {0, 25} | ||||
| 					layout.flags    = {.Fixed_Height} | ||||
| 					layout.padding  = to_ui_layout_side(4) | ||||
| 				} | ||||
| @@ -225,7 +228,7 @@ ui_screen_settings_menu :: proc( captures : rawptr = nil ) -> ( should_raise : b | ||||
| 					using title | ||||
| 					layout.anchor.ratio.x = 1.0 | ||||
| 					layout.margins.left   = 10 | ||||
| 					layout.text_alignment = {0, 0.0} | ||||
| 					title.layout.font_size = 12 | ||||
| 				} | ||||
|  | ||||
| 				input_box := ui_widget("settings_menu.engine_refresh.input_box", {.Mouse_Clickable, .Focusable, .Click_To_Focus}); { | ||||
| @@ -234,7 +237,7 @@ ui_screen_settings_menu :: proc( captures : rawptr = nil ) -> ( should_raise : b | ||||
| 					layout.margins.left   = 5 | ||||
| 					layout.padding.right  = 5 | ||||
| 					layout.size.min.x     = 80 | ||||
| 					style.corner_radii[0] = 0.35 | ||||
| 					style.corner_radii = { 3, 3, 3, 3 } | ||||
|  | ||||
| 					if      input_box.active do style.bg_color = app_color.input_box_bg_active | ||||
| 					else if input_box.hot    do style.bg_color = app_color.input_box_bg_hot | ||||
| @@ -287,7 +290,7 @@ ui_screen_settings_menu :: proc( captures : rawptr = nil ) -> ( should_raise : b | ||||
| 				scope( theme_table_row(is_even = true)) | ||||
| 				hb := ui_hbox(.Left_To_Right, "settings_menu.cam_min_zoom.hb"); { | ||||
| 					using hb | ||||
| 					layout.size.min = {0, 30} | ||||
| 					layout.size.min = {0, 25} | ||||
| 					layout.flags    = {.Fixed_Height} | ||||
| 					layout.padding  = to_ui_layout_side(4) | ||||
| 				} | ||||
| @@ -296,6 +299,7 @@ ui_screen_settings_menu :: proc( captures : rawptr = nil ) -> ( should_raise : b | ||||
| 					using title | ||||
| 					layout.anchor.ratio.x = 1.0 | ||||
| 					layout.margins.left   = 10 | ||||
| 					layout.font_size      = 12 | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| @@ -304,7 +308,7 @@ ui_screen_settings_menu :: proc( captures : rawptr = nil ) -> ( should_raise : b | ||||
| 				scope( theme_table_row(is_even = false)) | ||||
| 				hb := ui_hbox(.Left_To_Right, "settings_menu.cam_max_zoom.hb"); { | ||||
| 					using hb | ||||
| 					layout.size.min = {0, 30} | ||||
| 					layout.size.min = {0, 25} | ||||
| 					layout.flags    = {.Fixed_Height} | ||||
| 					layout.padding  = to_ui_layout_side(4) | ||||
| 				} | ||||
| @@ -313,6 +317,7 @@ ui_screen_settings_menu :: proc( captures : rawptr = nil ) -> ( should_raise : b | ||||
| 					using title | ||||
| 					layout.anchor.ratio.x = 1.0 | ||||
| 					layout.margins.left   = 10 | ||||
| 					layout.font_size      = 12 | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|   | ||||
| @@ -71,12 +71,12 @@ theme_drop_down_btn :: proc() -> UI_Theme | ||||
| 			anchor         = range2({0, 0},{}), | ||||
| 			alignment      = {0, 0}, | ||||
| 			text_alignment = {0.5, 0.5}, | ||||
| 			font_size      = 14, | ||||
| 			font_size      = 12, | ||||
| 			margins        = {0, 0, 0, 0}, | ||||
| 			padding        = {0, 0, 0, 0}, | ||||
| 			border_width   = 1, | ||||
| 			pos            = {0, 0}, | ||||
| 			size           = range2({0,20},{}) | ||||
| 			size           = range2({0,25},{}) | ||||
| 		} | ||||
| 		style := UI_Style { | ||||
| 			bg_color     = app_color.btn_bg_default, | ||||
| @@ -112,8 +112,8 @@ theme_drop_down_btn :: proc() -> UI_Theme | ||||
| theme_table_row :: proc( is_even : bool ) -> UI_Theme | ||||
| { | ||||
| 	@static theme  : UI_Theme | ||||
| 	@static loaded : b32 = false | ||||
| 	if ! loaded || true | ||||
| 	// @static loaded : b32 = false | ||||
| 	// if ! loaded || true | ||||
| 	{ | ||||
| 		app_color := app_color_theme() | ||||
| 		table_bg : RGBA8 | ||||
| @@ -128,7 +128,7 @@ theme_table_row :: proc( is_even : bool ) -> UI_Theme | ||||
| 			anchor         = range2({},{}), | ||||
| 			alignment      = {0, 0}, | ||||
| 			text_alignment = {0.5, 0.0}, | ||||
| 			font_size      = 16, | ||||
| 			font_size      = 10, | ||||
| 			margins        = {0, 0, 0, 0}, | ||||
| 			padding        = {0, 0, 0, 0}, | ||||
| 			border_width   = 0, | ||||
| @@ -159,7 +159,7 @@ theme_table_row :: proc( is_even : bool ) -> UI_Theme | ||||
| 			using style_combo.active | ||||
| 		} | ||||
| 		theme  = UI_Theme { layout_combo, style_combo } | ||||
| 		loaded = true | ||||
| 		// loaded = true | ||||
| 	} | ||||
| 	return theme | ||||
| } | ||||
| @@ -186,7 +186,7 @@ theme_window_bar :: proc() -> UI_Theme | ||||
| 		style := UI_Style { | ||||
| 			bg_color     = app_color.window_bar_bg, | ||||
| 			border_color = Color_Transparent, | ||||
| 			corner_radii = {}, | ||||
| 			corner_radii = {0, 0, 0, 0 }, | ||||
| 			blur_size    = 0, | ||||
| 			font         = get_state().default_font, | ||||
| 			text_color   = app_color.text_default, | ||||
| @@ -238,7 +238,7 @@ theme_window_bar_title :: proc() -> UI_Theme | ||||
| 		style := UI_Style { | ||||
| 			bg_color     = Color_Transparent, | ||||
| 			border_color = Color_Transparent, | ||||
| 			corner_radii = {}, | ||||
| 			corner_radii = {0, 0, 0, 0}, | ||||
| 			blur_size    = 0, | ||||
| 			font         = get_state().default_font, | ||||
| 			text_color   = app_color.text_default, | ||||
| @@ -335,7 +335,7 @@ theme_window_panel :: proc() -> UI_Theme | ||||
| 		style := UI_Style { | ||||
| 			bg_color     = app_color.window_panel_bg, | ||||
| 			border_color = app_color.window_panel_border, | ||||
| 			corner_radii = {}, | ||||
| 			corner_radii = { 0, 0, 0, 0 }, | ||||
| 			blur_size    = 0, | ||||
| 			font         = get_state().default_font, | ||||
| 			text_color   = app_color.text_default, | ||||
| @@ -421,7 +421,7 @@ theme_text :: proc() -> UI_Theme | ||||
| 			anchor         = range2({},{}), | ||||
| 			alignment      = {0, 0}, | ||||
| 			text_alignment = {0.0, 0.5}, | ||||
| 			font_size      = 14, | ||||
| 			font_size      = 12, | ||||
| 			margins        = {0, 0, 0, 0}, | ||||
| 			padding        = {0, 0, 0, 0}, | ||||
| 			border_width   = 0, | ||||
|   | ||||
| @@ -189,6 +189,6 @@ App_Thm_Light :: AppColorTheme { | ||||
| 	window_bar_bg           = RGBA8{ 155, 155, 155, 255}, | ||||
| 	window_btn_close_bg_hot = RGBA8{ 145, 135, 135, 255}, | ||||
|  | ||||
| 	window_panel_bg     = RGBA8 {135, 135, 135, 50}, // translucent_panel | ||||
| 	window_panel_bg     = RGBA8 {155, 155, 155, 50}, // translucent_panel | ||||
| 	window_panel_border = RGBA8{184, 184, 184, 255}, | ||||
| } | ||||
|   | ||||
| @@ -300,7 +300,7 @@ startup :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem | ||||
| 		// menu_bar.pos  = Vec2(app_window.extent) * { -1, 1 } | ||||
| 		menu_bar.size = {140, 40} | ||||
|  | ||||
| 		settings_menu.min_size = {250, 200} | ||||
| 		settings_menu.min_size = {260, 200} | ||||
| 	} | ||||
|  | ||||
| 	// Demo project setup | ||||
|   | ||||
| @@ -169,36 +169,38 @@ render_mode_screenspace :: proc( screen_extent : Extents2, screen_ui : ^UI_State | ||||
| 			screen_corners := screen_get_corners() | ||||
|  | ||||
| 			position   := screen_corners.top_left | ||||
| 			position.x += 2 | ||||
| 			position.y -= debug.draw_debug_text_y | ||||
|  | ||||
| 			content := str_fmt( format, ..args ) | ||||
| 			text_size := measure_text_size( content, default_font, 14.0, 0.0 ) | ||||
| 			debug_draw_text( content, position, 14.0 ) | ||||
| 			debug.draw_debug_text_y += text_size.y + 3 | ||||
| 			debug_draw_text( content, position, 10.0 ) | ||||
| 			debug.draw_debug_text_y += text_size.y | ||||
| 		} | ||||
|  | ||||
| 		profile("debug_text_vis") | ||||
| 		fps_size : f32 = 14.0 | ||||
| 		fps_msg       := str_fmt( "FPS: %0.2f", fps_avg) | ||||
| 		fps_msg_size  := measure_text_size( fps_msg, default_font, fps_size, 0.0 ) | ||||
| 		fps_msg_pos   := screen_get_corners().top_right - { fps_msg_size.x, fps_msg_size.y } | ||||
| 		debug_draw_text( fps_msg, fps_msg_pos, fps_size, color = Color_Red ) | ||||
| 		if true { | ||||
| 			fps_size : f32 = 14.0 | ||||
| 			fps_msg       := str_fmt( "FPS: %0.2f", fps_avg) | ||||
| 			fps_msg_size  := measure_text_size( fps_msg, default_font, fps_size, 0.0 ) | ||||
| 			fps_msg_pos   := screen_get_corners().top_right - { fps_msg_size.x, fps_msg_size.y } | ||||
| 			debug_draw_text( fps_msg, fps_msg_pos, fps_size, color = Color_Red ) | ||||
| 		} | ||||
|  | ||||
| 		debug_text( "Screen Width : %v", screen_size.x ) | ||||
| 		debug_text( "Screen Height: %v", screen_size.y ) | ||||
| 		debug_text( "frametime_target_ms       : %f ms", frametime_target_ms ) | ||||
| 		debug_text( "frametime (work)          : %0.3f ms", frametime_delta_ms ) | ||||
| 		debug_text( "frametime_last_elapsed_ms : %f ms", frametime_elapsed_ms ) | ||||
| 		if false { | ||||
| 			debug_text( "Screen Width : %v", screen_size.x ) | ||||
| 			debug_text( "Screen Height: %v", screen_size.y ) | ||||
| 			debug_text( "frametime_target_ms       : %f ms", frametime_target_ms ) | ||||
| 			debug_text( "frametime (work)          : %0.3f ms", frametime_delta_ms ) | ||||
| 			debug_text( "frametime_last_elapsed_ms : %f ms", frametime_elapsed_ms ) | ||||
| 		} | ||||
| 		if replay.mode == ReplayMode.Record { | ||||
| 			debug_text( "Recording Input") | ||||
| 		} | ||||
| 		if replay.mode == ReplayMode.Playback { | ||||
| 			debug_text( "Replaying Input") | ||||
| 		} | ||||
| 		debug_text("Zoom Target: %v", project.workspace.zoom_target) | ||||
|  | ||||
| 		if true | ||||
| 		if false | ||||
| 		{ | ||||
| 			using input_events | ||||
|  | ||||
| @@ -221,11 +223,12 @@ render_mode_screenspace :: proc( screen_extent : Extents2, screen_ui : ^UI_State | ||||
| 			debug_text("Mouse Position (Workspace View): %0.2f", screen_to_ws_view_pos(input.mouse.pos) ) | ||||
| 		} | ||||
|  | ||||
| 		if true | ||||
| 		if false | ||||
| 		{ | ||||
| 			ui := & project.workspace.ui | ||||
|  | ||||
| 			debug_text("Workspace Cam : %v", project.workspace.cam) | ||||
| 			debug_text("Zoom Target   : %v", project.workspace.zoom_target) | ||||
|  | ||||
| 			debug_text("Box Count (Workspace): %v", ui.built_box_count ) | ||||
|  | ||||
| @@ -240,7 +243,7 @@ render_mode_screenspace :: proc( screen_extent : Extents2, screen_ui : ^UI_State | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if true | ||||
| 		if false | ||||
| 		{ | ||||
| 			ui := & screen_ui | ||||
|  | ||||
| @@ -257,7 +260,7 @@ render_mode_screenspace :: proc( screen_extent : Extents2, screen_ui : ^UI_State | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if true { | ||||
| 		if false { | ||||
| 			state.config.font_size_canvas_scalar = 1.5 | ||||
| 			zoom_adjust_size := 16 * state.project.workspace.cam.zoom | ||||
| 			over_sample      := f32(state.config.font_size_canvas_scalar) | ||||
| @@ -498,16 +501,23 @@ render_ui_via_box_tree :: proc( ui : ^UI_State, screen_extent : Vec2, ve_ctx : ^ | ||||
|  | ||||
| 		GP_Render: | ||||
| 		{ | ||||
| 			corner_radii_total : f32 = 0 | ||||
| 			for radius in style.corner_radii do corner_radii_total += radius | ||||
|  | ||||
| 			profile("draw_shapes") | ||||
| 			if style.bg_color.a != 0 | ||||
| 			{ | ||||
| 				draw_rect( bounds, style.bg_color ) | ||||
| 				render_set_color( style.bg_color ) | ||||
| 				if corner_radii_total > 0 do draw_rect_rounded( bounds, style.corner_radii, 16 ) | ||||
| 				else                      do draw_rect( bounds) | ||||
| 				shape_enqueued = true | ||||
| 			} | ||||
|  | ||||
| 			if style.border_color.a != 0 && border_width > 0 { | ||||
| 				render_set_color( style.border_color ) | ||||
| 				draw_rect_border( bounds, border_width ) | ||||
|  | ||||
| 				if corner_radii_total > 0 do draw_rect_rounded_border( bounds, style.corner_radii, border_width, 16 ) | ||||
| 				else                      do draw_rect_border( bounds, border_width ) | ||||
| 				shape_enqueued = true | ||||
| 			} | ||||
|  | ||||
| @@ -517,10 +527,12 @@ render_ui_via_box_tree :: proc( ui : ^UI_State, screen_extent : Vec2, ve_ctx : ^ | ||||
| 			{ | ||||
| 				render_set_color( RGBA8_Debug_UI_Padding_Bounds ) | ||||
| 				draw_rect_border( computed.padding, line_thickness ) | ||||
| 				shape_enqueued = true | ||||
| 			} | ||||
| 			else if debug.draw_ui_content_bounds { | ||||
| 				render_set_color( RGBA8_Debug_UI_Content_Bounds ) | ||||
| 				draw_rect_border( computed.content, line_thickness ) | ||||
| 				shape_enqueued = true | ||||
| 			} | ||||
|  | ||||
| 			if debug.draw_ui_box_bounds_points | ||||
| @@ -578,7 +590,8 @@ render_ui_via_box_list :: proc( render_list : []UI_RenderBoxInfo, screen_extent | ||||
| 			// profile("draw_shapes") | ||||
| 			if style.bg_color.a != 0 | ||||
| 			{ | ||||
| 				draw_rect( bounds, style.bg_color ) | ||||
| 				render_set_color( style.bg_color ) | ||||
| 				draw_rect( bounds ) | ||||
| 				shape_enqueued = true | ||||
| 			} | ||||
|  | ||||
| @@ -643,15 +656,72 @@ draw_filled_circle :: proc(x, y, radius: f32, edges: int) | ||||
| 	gp.draw_filled_triangles(raw_data(triangles), u32(len(triangles))) | ||||
| } | ||||
|  | ||||
| draw_rect :: proc( rect : Range2, color : RGBA8 ) { | ||||
| draw_rect :: proc( rect : Range2 ) { | ||||
| 	using rect | ||||
| 	render_set_color( color ) | ||||
|  | ||||
| 	size     := max - min | ||||
| 	position := min | ||||
| 	gp.draw_filled_rect( position.x, position.y, size.x, size.y ) | ||||
| } | ||||
|  | ||||
| // Note(Ed): This is an inefficint solution to rendering rounded rectangles | ||||
| // Eventually when sokoL_gp is ported to Odin it would be best to implement these using a custom shader | ||||
| // Uses triangulation from the center. (UVs are problably weird but wont matter for my use case) | ||||
| draw_rect_rounded :: proc(rect: Range2, radii: [4]f32, segments: u32) | ||||
| { | ||||
| 	segments := i32(segments) | ||||
| 	width  := rect.max.x - rect.min.x | ||||
| 	height := rect.max.y - rect.min.y | ||||
|  | ||||
| 	using Corner | ||||
|  | ||||
| 	max_radius := min(width, height) * 0.5 | ||||
| 	corner_radii := [4]f32{ | ||||
| 		min(radii[ Top_Left    ], max_radius), | ||||
| 		min(radii[ Top_Right   ], max_radius), | ||||
| 		min(radii[ Bottom_Right], max_radius), | ||||
| 		min(radii[ Bottom_Left ], max_radius), | ||||
| 	} | ||||
| 	top_left     := corner_radii[ Top_Left     ] | ||||
| 	top_right    := corner_radii[ Top_Right    ] | ||||
| 	bottom_left  := corner_radii[ Bottom_Left  ] | ||||
| 	bottom_right := corner_radii[ Bottom_Right ] | ||||
|  | ||||
| 	total_vertices  := (segments + 1) * 4 | ||||
| 	total_triangles := total_vertices | ||||
|  | ||||
| 	vertices  := make( []gp.Point,    total_vertices ) | ||||
| 	triangles := make( []gp.Triangle, total_triangles) | ||||
|  | ||||
| 	add_corner_vertices :: proc(vertices : []gp.Point, offset : i32, cx, cy, radius : f32, start_angle : f32, segments : i32) | ||||
| 	{ | ||||
| 		half_pi :: math.PI / 2 | ||||
| 		for segment in i32(0) ..= segments { | ||||
| 			angle := start_angle + half_pi * (f32(segment) / f32(segments)) | ||||
| 			x     := cx + radius * math.cos(angle) | ||||
| 			y     := cy + radius * math.sin(angle) | ||||
| 			vertices[ offset + segment ] = gp.Point{x, y} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	half_pi :: math.PI / 2 | ||||
|  | ||||
| 	// Add vertices for each corner | ||||
| 	add_corner_vertices( vertices, 0 * (segments + 1), rect.min.x + top_left,     rect.min.y + top_left,     top_left,         math.PI, segments ) | ||||
| 	add_corner_vertices( vertices, 1 * (segments + 1), rect.max.x - top_right,    rect.min.y + top_right,    top_right,    3 * half_pi, segments ) | ||||
| 	add_corner_vertices( vertices, 2 * (segments + 1), rect.max.x - bottom_left,  rect.max.y - bottom_left,  bottom_left,            0, segments ) | ||||
| 	add_corner_vertices( vertices, 3 * (segments + 1), rect.min.x + bottom_right, rect.max.y - bottom_right, bottom_right,     half_pi, segments ) | ||||
|  | ||||
| 	// Create triangles using fan triangulation | ||||
| 	center := gp.Point{ (rect.min.x + rect.max.x) * 0.5, (rect.min.y + rect.max.y) * 0.5 } | ||||
| 	for vertex in 0 ..< total_vertices { | ||||
| 			next             := (vertex + 1) % total_vertices | ||||
| 			triangles[vertex] = gp.Triangle { center, vertices[vertex], vertices[next] } | ||||
| 	} | ||||
|  | ||||
| 	// Draw the filled triangles | ||||
| 	gp.draw_filled_triangles(raw_data(triangles), cast(u32)len(triangles)) | ||||
| } | ||||
|  | ||||
| draw_rect_border :: proc( rect : Range2, border_width: f32) | ||||
| { | ||||
| 	rect_size    := rect.max - rect.min | ||||
| @@ -666,6 +736,74 @@ draw_rect_border :: proc( rect : Range2, border_width: f32) | ||||
| 	gp.draw_filled_rects( raw_data(borders), u32(len(borders)) ) | ||||
| } | ||||
|  | ||||
| draw_rect_rounded_border :: proc(rect: Range2, radii: [4]f32, border_width: f32, segments: u32) | ||||
| { | ||||
| 	width  := rect.max.x - rect.min.x | ||||
| 	height := rect.max.y - rect.min.y | ||||
|  | ||||
| 	using Corner | ||||
|  | ||||
| 	// Ensure radii are not too large | ||||
| 	max_radius := min(width, height) * 0.5 | ||||
| 	corner_radii := [4]f32{ | ||||
| 		min(radii[0], max_radius), | ||||
| 		min(radii[1], max_radius), | ||||
| 		min(radii[2], max_radius), | ||||
| 		min(radii[3], max_radius), | ||||
| 	} | ||||
| 	top_left     := corner_radii[ Top_Left     ] | ||||
| 	top_right    := corner_radii[ Top_Right    ] | ||||
| 	bottom_left  := corner_radii[ Bottom_Left  ] | ||||
| 	bottom_right := corner_radii[ Bottom_Right ] | ||||
|  | ||||
| 	// Ensure border width is not too large | ||||
| 	border_width := min(border_width, max_radius) | ||||
|  | ||||
| 	// Calculate the extents of the border rectangles | ||||
| 	left   := rect.min.x + max(top_left,    bottom_left) | ||||
| 	right  := rect.max.x - max(top_right,   bottom_right) | ||||
| 	top    := rect.min.y + max(top_left,    top_right) | ||||
| 	bottom := rect.max.y - max(bottom_left, bottom_right) | ||||
|  | ||||
| 	// Draw border rectangles | ||||
| 	gp.draw_filled_rect(left,                      rect.min.y,                right - left, border_width)	// Top | ||||
| 	gp.draw_filled_rect(left,                      rect.max.y - border_width, right - left, border_width)	// Bottom | ||||
| 	gp.draw_filled_rect(rect.min.x,                top,                       border_width, bottom - top) // Left | ||||
| 	gp.draw_filled_rect(rect.max.x - border_width, top,                       border_width, bottom - top) // Right | ||||
|  | ||||
| 	draw_corner_border :: proc( x, y : f32, outer_radius, inner_radius : f32, start_angle : f32, segments : u32 ) | ||||
| 	{ | ||||
| 		if outer_radius <= inner_radius do return | ||||
| 		triangles := make( []gp.Triangle, int(segments) * 2 ) | ||||
|  | ||||
| 		half_pi     :: math.PI / 2 | ||||
| 		segment_quo := 1.0 / f32(segments) | ||||
| 		for segment in 0 ..< segments | ||||
| 		{ | ||||
| 				angle1 := start_angle + half_pi * f32(segment)     * segment_quo | ||||
| 				angle2 := start_angle + half_pi * f32(segment + 1) * segment_quo | ||||
|  | ||||
| 				outer1 := gp.Vec2{x + outer_radius * math.cos(angle1), y + outer_radius * math.sin(angle1)} | ||||
| 				outer2 := gp.Vec2{x + outer_radius * math.cos(angle2), y + outer_radius * math.sin(angle2)} | ||||
| 				inner1 := gp.Vec2{x + inner_radius * math.cos(angle1), y + inner_radius * math.sin(angle1)} | ||||
| 				inner2 := gp.Vec2{x + inner_radius * math.cos(angle2), y + inner_radius * math.sin(angle2)} | ||||
|  | ||||
| 				triangles[segment * 2    ] = gp.Triangle { outer1, outer2, inner1 } | ||||
| 				triangles[segment * 2 + 1] = gp.Triangle { inner1, outer2, inner2 } | ||||
| 		} | ||||
|  | ||||
| 		gp.draw_filled_triangles(raw_data(triangles), u32(len(triangles))) | ||||
| 	} | ||||
|  | ||||
| 	half_pi :: math.PI / 2 | ||||
|  | ||||
| 	// Draw corner borders | ||||
| 	draw_corner_border(rect.min.x + top_left,     rect.min.y + top_left,     top_left,     max(top_left     - border_width, 0),     math.PI, segments) | ||||
| 	draw_corner_border(rect.max.x - top_right,    rect.min.y + top_right,    top_right,    max(top_right    - border_width, 0), 3 * half_pi, segments) | ||||
| 	draw_corner_border(rect.min.x + bottom_left,  rect.max.y - bottom_left,  bottom_left,  max(bottom_left  - border_width, 0),     half_pi, segments) | ||||
| 	draw_corner_border(rect.max.x - bottom_right, rect.max.y - bottom_right, bottom_right, max(bottom_right - border_width, 0),           0, segments) | ||||
| } | ||||
|  | ||||
| // Draw text using a string and normalized render coordinates | ||||
| draw_text_string_pos_norm :: proc( content : string, id : FontID, size : f32, pos : Vec2, color := Color_White, scale : f32 = 1.0 ) | ||||
| { | ||||
|   | ||||
| @@ -10,10 +10,10 @@ Corner :: enum i32 { | ||||
| 	_01, | ||||
| 	_10, | ||||
| 	_11, | ||||
| 	TopLeft     = _00, | ||||
| 	TopRight    = _01, | ||||
| 	BottomLeft  = _10, | ||||
| 	BottomRight = _11, | ||||
| 	Top_Left     = _00, | ||||
| 	Top_Right    = _01, | ||||
| 	Bottom_Left  = _10, | ||||
| 	Bottom_Right = _11, | ||||
| 	Count = 4, | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -1,5 +1,9 @@ | ||||
| package sectr | ||||
|  | ||||
| BoxCorners :: struct { | ||||
| 	top_left, top_right, bottom_right, bottom_left : f32, | ||||
| } | ||||
|  | ||||
| // TODO(Ed): We problably can embedd this info into the UI_Layout with the regular text_alignment | ||||
| UI_TextAlign :: enum u32 { | ||||
| 	Left, | ||||
| @@ -20,7 +24,6 @@ UI_Style :: struct { | ||||
| 	bg_color     : RGBA8, | ||||
| 	border_color : RGBA8, | ||||
|  | ||||
| 	// TODO(Ed): We cannot support individual corners unless we add it to raylib (or finally change the rendering backend) | ||||
| 	corner_radii : [Corner.Count]f32, | ||||
|  | ||||
| 	// TODO(Ed) : Add support for this eventually | ||||
|   | ||||
| @@ -277,7 +277,7 @@ ui_resizable_handles :: proc( parent : ^UI_Widget, pos : ^Vec2, size : ^Vec2, | ||||
| 			style := UI_Style { | ||||
| 				bg_color     = Color_Transparent, | ||||
| 				border_color = Color_Transparent, | ||||
| 				corner_radii = {5, 0, 0, 0}, | ||||
| 				corner_radii = {5, 5, 5, 5}, | ||||
| 				blur_size    = 0, | ||||
| 				font         = get_state().default_font, | ||||
| 				text_color   = app_color.text_default, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user