@tool class_name ForgedStyle extends StyleBox ## Vector-drawn plate for the Saumwacht theme: chamfered corners, a bronze edge, ## an inset line and an optional top bevel. Drawn per frame, so it stays crisp at any UI scale. @export var fill_top: Color = Color("1b2027") @export var fill_bottom: Color = Color("12161b") @export var edge: Color = Color("8a6a3c") @export var edge_width: float = 1.5 @export var inner: Color = Color(1, 1, 1, .05) @export var inner_inset: float = 4.0 @export var chamfer: float = 7.0 @export var highlight: Color = Color(1, 1, 1, 0) @export var shadow: Color = Color(0, 0, 0, 0) @export var shadow_size: float = 0.0 @export var ornaments: bool = false @export var ornament_color: Color = Color("c99a58") ## Grows the drawing outside the control; used for focus rings that must not cover content. @export var grow: float = 0.0 @export var draw_fill: bool = true static func plate_points(rect: Rect2, cut: float) -> PackedVector2Array: var c: float = minf(cut, minf(rect.size.x, rect.size.y) * .5) var p: Vector2 = rect.position var e: Vector2 = rect.end return PackedVector2Array([Vector2(p.x + c, p.y), Vector2(e.x - c, p.y), Vector2(e.x, p.y + c), Vector2(e.x, e.y - c), Vector2(e.x - c, e.y), Vector2(p.x + c, e.y), Vector2(p.x, e.y - c), Vector2(p.x, p.y + c)]) func _draw(item: RID, rect: Rect2) -> void: var r: Rect2 = rect.grow(grow) if r.size.x < 2.0 or r.size.y < 2.0: return if shadow.a > 0.0 and shadow_size > 0.0: for layer: int in range(3): var spread: float = shadow_size * float(layer + 1) / 3.0 var soft := Color(shadow.r, shadow.g, shadow.b, shadow.a / 3.0) if draw_fill: var points := plate_points(Rect2(r.position + Vector2(0, spread * .5), r.size).grow(spread), chamfer + spread) RenderingServer.canvas_item_add_polygon(item, points, PackedColorArray([soft])) else: # Rings only glow outwards; the control underneath stays untinted. var halo := plate_points(r.grow(spread), chamfer + spread) halo.append(halo[0]) RenderingServer.canvas_item_add_polyline(item, halo, PackedColorArray([soft]), shadow_size / 3.0 + 1.0, true) if draw_fill: var points := plate_points(r, chamfer) var colors := PackedColorArray() for point: Vector2 in points: colors.append(fill_top.lerp(fill_bottom, clampf((point.y - r.position.y) / r.size.y, 0.0, 1.0))) RenderingServer.canvas_item_add_polygon(item, points, colors) if highlight.a > 0.0: var y: float = r.position.y + edge_width + 1.0 RenderingServer.canvas_item_add_line(item, Vector2(r.position.x + chamfer, y), Vector2(r.end.x - chamfer, y), highlight, 1.0, true) if inner.a > 0.0 and inner_inset > 0.0: var inset := plate_points(r.grow(-inner_inset), maxf(1.0, chamfer - inner_inset * .45)) inset.append(inset[0]) RenderingServer.canvas_item_add_polyline(item, inset, PackedColorArray([inner]), 1.0, true) if edge.a > 0.0 and edge_width > 0.0: var outline := plate_points(r.grow(-edge_width * .5), chamfer) outline.append(outline[0]) RenderingServer.canvas_item_add_polyline(item, outline, PackedColorArray([edge]), edge_width, true) if ornaments: # Small rivet diamonds on the long edges mark forged panels without adding frames. for x: float in [r.position.x + r.size.x * .5]: for y: float in [r.position.y, r.end.y]: var size: float = 3.5 var diamond := PackedVector2Array([Vector2(x, y - size), Vector2(x + size, y), Vector2(x, y + size), Vector2(x - size, y)]) RenderingServer.canvas_item_add_polygon(item, diamond, PackedColorArray([ornament_color]))