Unveränderter Ausgangsstand inklusive Masterprompt und Konzeptbildern unter assets/. .godot/ und docs/screenshots/ bleiben laut .gitignore unversioniert; letztere sind unter ../backups gesichert. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
69 lines
3.5 KiB
GDScript
69 lines
3.5 KiB
GDScript
@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]))
|