Randoloot/scripts/ui/orbital_contact_style.gd
2026-10-18 18:47:18 +02:00

73 lines
3.2 KiB
GDScript

extends RefCounted
## Compact translucent cards attached to objects in the world canvas.
static func panel_style(accent: Color) -> StyleBoxFlat:
var style := StyleBoxFlat.new()
style.bg_color = Color(0.018,0.041,0.063,0.84)
style.border_color = Color(accent,0.55)
style.set_border_width_all(1)
style.border_width_top = 2
style.set_corner_radius_all(7)
style.content_margin_left = 12
style.content_margin_right = 12
style.content_margin_top = 10
style.content_margin_bottom = 10
style.shadow_color = Color(0,0,0,0.28)
style.shadow_size = 7
style.shadow_offset = Vector2(0,3)
return style
static func compact_button(button: Button, accent: Color) -> void:
preload("res://scripts/ui/hud_button_style.gd").apply(button,accent)
button.custom_minimum_size.y = 30
button.add_theme_font_size_override("font_size",11)
for state in ["normal","hover","pressed","disabled"]:
var style := button.get_theme_stylebox(state).duplicate() as StyleBoxFlat
style.bg_color.a = 0.8
style.content_margin_top = 4
style.content_margin_bottom = 4
style.content_margin_left = 9
style.content_margin_right = 9
style.shadow_size = 0
style.set_corner_radius_all(4)
button.add_theme_stylebox_override(state,style)
static func hud_obstacles(hud: Node) -> Array[Rect2]:
var boxes: Array[Rect2] = []
if hud == null: return boxes
for name in ["CaptainPanel","CaptainEquipment","CaptainGearInventory","MissionObjectives","ShipDrawer","PassiveCaptainPanel","PassiveShipPanel"]:
var control := hud.get_node_or_null(NodePath(name)) as Control
if control != null and control.is_visible_in_tree(): boxes.append(control.get_global_rect().grow(6))
return boxes
static func beside(center: Vector2, radius: float, extent: Vector2, viewport: Vector2, obstacles: Array[Rect2] = [], prefer_right := true, vertical_radius := -1.0) -> Vector2:
var gap := 14.0
var vertical := radius if vertical_radius < 0 else vertical_radius
var right := center + Vector2(radius+gap,-extent.y*0.5)
var left := center - Vector2(radius+gap+extent.x,extent.y*0.5)
var candidates: Array[Vector2] = [right,left]
if not prefer_right: candidates.reverse()
candidates.append(center+Vector2(-extent.x*0.5,-vertical-gap-extent.y))
candidates.append(center+Vector2(-extent.x*0.5,vertical+gap))
# Additional lanes prevent two cards from clipping one another's headers.
for obstacle in obstacles:
candidates.append(Vector2(center.x-extent.x*0.5,obstacle.position.y-gap-extent.y))
candidates.append(Vector2(center.x-extent.x*0.5,obstacle.end.y+gap))
var chosen := Vector2.ZERO
var best := INF
var low := Vector2(10,88)
var high := Vector2(maxf(low.x,viewport.x-extent.x-10),maxf(low.y,viewport.y-extent.y-118))
for index in candidates.size():
var candidate := candidates[index]
var clamped := candidate.clamp(low,high)
var box := Rect2(clamped,extent)
var score := candidate.distance_to(clamped) + index*8.0
# Avoid covering the object if an edge forces the card to change sides.
var object_box := Rect2(center-Vector2(radius,vertical),Vector2(radius,vertical)*2)
if box.intersects(object_box): score += box.intersection(object_box).get_area()*0.1
for obstacle in obstacles:
if box.intersects(obstacle): score += box.intersection(obstacle).get_area()
if score < best:
best = score
chosen = clamped
return chosen