exchanger-themes/tools/preview/BindingOverlay.gd
Danil Iarosh ca52efbedc Initial commit: Exchanger Theme DLC Builder
Godot 4.7 project for authoring, previewing, validating, and building Exchanger PCK themes. Includes the example and space-pixel themes, binding contracts, editor tooling, validation/build scripts, and project documentation.
2026-09-22 11:43:13 +03:00

77 lines
2.7 KiB
GDScript

extends Control
const ELEMENT_META_KEY := &"exchanger_binding_id"
const SCREEN_META_KEY := &"exchanger_screen_binding_id"
const LABEL_FONT_SIZE := 10
const LABEL_HEIGHT := 22.0
const LABEL_PADDING := 5.0
var target: Node
func _ready() -> void:
mouse_filter = Control.MOUSE_FILTER_IGNORE
set_process(true)
func _process(_delta: float) -> void:
queue_redraw()
func _draw() -> void:
if target == null or not is_instance_valid(target):
return
for node in _all_nodes(target):
if (not node.has_meta(ELEMENT_META_KEY) and not node.has_meta(SCREEN_META_KEY)) or not node is CanvasItem:
continue
var canvas_item := node as CanvasItem
if not canvas_item.is_visible_in_tree():
continue
var binding_id := str(
node.get_meta(ELEMENT_META_KEY)
if node.has_meta(ELEMENT_META_KEY)
else node.get_meta(SCREEN_META_KEY)
)
var bounds := _bounds_for(canvas_item)
draw_rect(bounds, Color(1.0, 0.72, 0.08, 0.92), false, 2.0)
var label_width := minf(size.x - 8.0, maxf(80.0, binding_id.length() * 6.0 + LABEL_PADDING * 2.0))
var label_rect := Rect2(bounds.position, Vector2(label_width, LABEL_HEIGHT))
label_rect.position.x = clampf(label_rect.position.x, 4.0, size.x - label_width - 4.0)
if label_rect.position.y < 28.0:
label_rect.position.y = bounds.end.y
draw_rect(label_rect, Color(0.02, 0.06, 0.14, 0.94), true)
draw_rect(label_rect, Color(1.0, 0.72, 0.08, 1.0), false, 1.0)
draw_string(
ThemeDB.fallback_font,
label_rect.position + Vector2(LABEL_PADDING, 16.0),
binding_id,
HORIZONTAL_ALIGNMENT_LEFT,
label_width - LABEL_PADDING * 2.0,
LABEL_FONT_SIZE,
Color.WHITE
)
func _bounds_for(item: CanvasItem) -> Rect2:
var inverse := get_global_transform().affine_inverse()
if item is Control:
var control := item as Control
var top_left := inverse * control.get_global_transform_with_canvas() * Vector2.ZERO
var bottom_right := inverse * control.get_global_transform_with_canvas() * control.size
return Rect2(top_left, bottom_right - top_left).abs()
if item is Node2D:
var point := inverse * (item as Node2D).get_global_transform_with_canvas().origin
return Rect2(point - Vector2(8.0, 8.0), Vector2(16.0, 16.0))
return Rect2(Vector2.ZERO, Vector2(16.0, 16.0))
func _all_nodes(root: Node) -> Array[Node]:
var result: Array[Node] = [root]
var cursor := 0
while cursor < result.size():
var current := result[cursor]
for child in current.get_children():
result.append(child)
cursor += 1
return result