fix(ui): star map info panel — dynamic height measurement
Panel now measures all variable content (GTTR text, adjacent systems) before calculating height. Fixes clipping on hub systems with many neighbors and long GTTR excerpts. Unified separator spacing (8px). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
+94
-73
@@ -403,57 +403,15 @@ func _draw_info_panel(sz: Vector2) -> void:
|
||||
var font := get_theme_default_font()
|
||||
var panel_w: float = POPUP_WIDTH
|
||||
var pad: float = POPUP_PADDING
|
||||
var sep_h: float = 8.0 # separator line + spacing
|
||||
var inner_w: float = panel_w - pad * 2.0
|
||||
var sep_color := Color(COLOR_TEXT.r, COLOR_TEXT.g, COLOR_TEXT.b, 0.12)
|
||||
|
||||
# Measure GTTR text height first so we can size the panel
|
||||
var gttr: String = node.get("gttr_excerpt", "")
|
||||
# Strip markdown bold markers for display
|
||||
gttr = gttr.replace("**", "")
|
||||
var gttr_block_h: float = 0.0
|
||||
if not gttr.is_empty():
|
||||
var gttr_size: Vector2 = font.get_multiline_string_size(
|
||||
gttr, HORIZONTAL_ALIGNMENT_LEFT, inner_w, POPUP_GTTR_FONT_SIZE,
|
||||
POPUP_GTTR_MAX_LINES)
|
||||
gttr_block_h = gttr_size.y + 6.0
|
||||
|
||||
# Fixed rows: name, id, star+hop, corridor, bodies+pop, adjacent, separator lines
|
||||
var fixed_h: float = (
|
||||
POPUP_LINE_H * 2.0 # name + id
|
||||
+ 4.0 # separator
|
||||
+ POPUP_LINE_H * 3.0 # star+hop, corridor, bodies+pop
|
||||
+ 4.0 # separator
|
||||
+ gttr_block_h
|
||||
+ 4.0 # separator (before adjacent)
|
||||
+ POPUP_LINE_H # adjacent systems label
|
||||
+ pad * 2.0
|
||||
)
|
||||
var panel_h: float = fixed_h
|
||||
|
||||
var panel_pos := Vector2(sz.x - panel_w - POPUP_MARGIN, POPUP_MARGIN)
|
||||
var x: float = panel_pos.x + pad
|
||||
var y: float = panel_pos.y + pad + POPUP_LINE_H # baseline offset
|
||||
|
||||
# Background + border
|
||||
draw_rect(Rect2(panel_pos, Vector2(panel_w, panel_h)), COLOR_INFO_BG)
|
||||
draw_rect(Rect2(panel_pos, Vector2(panel_w, panel_h)),
|
||||
Color(COLOR_TEXT.r, COLOR_TEXT.g, COLOR_TEXT.b, 0.15), false, 1.0)
|
||||
|
||||
# ── System name ──────────────────────────────────────────────────────────
|
||||
# ── Prepare all text content before measuring ────────────────────────────
|
||||
var sys_name: String = node.get("proper_name", "")
|
||||
if sys_name.is_empty():
|
||||
sys_name = node.get("system_id", "Unknown")
|
||||
draw_string(font, Vector2(x, y), sys_name, HORIZONTAL_ALIGNMENT_LEFT, inner_w, 15, COLOR_TEXT)
|
||||
y += POPUP_LINE_H
|
||||
|
||||
draw_string(font, Vector2(x, y), node.get("system_id", ""), HORIZONTAL_ALIGNMENT_LEFT, inner_w, 10, COLOR_TEXT_DIM)
|
||||
y += POPUP_LINE_H
|
||||
|
||||
# Separator
|
||||
draw_line(Vector2(x, y + 1.0), Vector2(panel_pos.x + panel_w - pad, y + 1.0),
|
||||
Color(COLOR_TEXT.r, COLOR_TEXT.g, COLOR_TEXT.b, 0.12), 1.0)
|
||||
y += 6.0
|
||||
|
||||
# ── Stats block ──────────────────────────────────────────────────────────
|
||||
var star_type: String = node.get("star_type", "")
|
||||
var hop: int = int(node.get("hop_distance", 0))
|
||||
var stat_line_1: String
|
||||
@@ -461,13 +419,9 @@ func _draw_info_panel(sz: Vector2) -> void:
|
||||
stat_line_1 = "Hop %d from Gateway" % hop
|
||||
else:
|
||||
stat_line_1 = "%s star · hop %d" % [star_type, hop]
|
||||
draw_string(font, Vector2(x, y), stat_line_1, HORIZONTAL_ALIGNMENT_LEFT, inner_w, 11, COLOR_TEXT_DIM)
|
||||
y += POPUP_LINE_H
|
||||
|
||||
var sector_str: String = node.get("geographic_sector", "unknown").replace("_", " ").to_upper()
|
||||
var sector_color: Color = SECTOR_COLORS.get(node.get("geographic_sector", ""), COLOR_TEXT_DIM)
|
||||
draw_string(font, Vector2(x, y), sector_str + " corridor", HORIZONTAL_ALIGNMENT_LEFT, inner_w, 11, sector_color)
|
||||
y += POPUP_LINE_H
|
||||
|
||||
var bodies: String = node.get("bodies", "")
|
||||
var population: String = node.get("population", "")
|
||||
@@ -479,39 +433,106 @@ func _draw_info_panel(sz: Vector2) -> void:
|
||||
elif not population.is_empty():
|
||||
stat_line_3 = "Population: " + population
|
||||
else:
|
||||
stat_line_3 = "%d aperture%s · %s" % [
|
||||
stat_line_3 = "%d aperture%s" % [
|
||||
int(node.get("aperture_count", 0)),
|
||||
"s" if int(node.get("aperture_count", 0)) != 1 else "",
|
||||
node.get("gate_topology", "")]
|
||||
draw_string(font, Vector2(x, y), stat_line_3, HORIZONTAL_ALIGNMENT_LEFT, inner_w, 11, COLOR_TEXT_DIM)
|
||||
y += POPUP_LINE_H
|
||||
"s" if int(node.get("aperture_count", 0)) != 1 else ""]
|
||||
|
||||
# ── GTTR excerpt ─────────────────────────────────────────────────────────
|
||||
if not gttr.is_empty():
|
||||
draw_line(Vector2(x, y + 1.0), Vector2(panel_pos.x + panel_w - pad, y + 1.0),
|
||||
Color(COLOR_TEXT.r, COLOR_TEXT.g, COLOR_TEXT.b, 0.12), 1.0)
|
||||
y += 6.0
|
||||
draw_multiline_string(font, Vector2(x, y), gttr, HORIZONTAL_ALIGNMENT_LEFT,
|
||||
inner_w, POPUP_GTTR_FONT_SIZE, POPUP_GTTR_MAX_LINES,
|
||||
Color(COLOR_TEXT.r, COLOR_TEXT.g, COLOR_TEXT.b, 0.75))
|
||||
y += gttr_block_h
|
||||
var gttr: String = node.get("gttr_excerpt", "").replace("**", "")
|
||||
|
||||
# ── Adjacent systems ──────────────────────────────────────────────────────
|
||||
draw_line(Vector2(x, y + 1.0), Vector2(panel_pos.x + panel_w - pad, y + 1.0),
|
||||
Color(COLOR_TEXT.r, COLOR_TEXT.g, COLOR_TEXT.b, 0.12), 1.0)
|
||||
y += 6.0
|
||||
var adj: Array = node.get("adjacent_systems", [])
|
||||
if adj.is_empty():
|
||||
draw_string(font, Vector2(x, y), "No gate connections", HORIZONTAL_ALIGNMENT_LEFT, inner_w, 10, COLOR_TEXT_DIM)
|
||||
else:
|
||||
var adj_line: String = ""
|
||||
if not adj.is_empty():
|
||||
var adj_names: Array = []
|
||||
for neighbor_id: String in adj:
|
||||
var neighbor: Dictionary = _node_lookup.get(neighbor_id, {})
|
||||
var n_name: String = neighbor.get("proper_name", "")
|
||||
adj_names.append(n_name if not n_name.is_empty() else neighbor_id)
|
||||
var adj_line: String = " · ".join(adj_names)
|
||||
draw_multiline_string(font, Vector2(x, y), adj_line, HORIZONTAL_ALIGNMENT_LEFT,
|
||||
inner_w, 10, 2, COLOR_TEXT_DIM)
|
||||
adj_line = " · ".join(adj_names)
|
||||
|
||||
# ── Measure variable-height blocks ───────────────────────────────────────
|
||||
var gttr_h: float = 0.0
|
||||
if not gttr.is_empty():
|
||||
gttr_h = font.get_multiline_string_size(
|
||||
gttr, HORIZONTAL_ALIGNMENT_LEFT, inner_w,
|
||||
POPUP_GTTR_FONT_SIZE, POPUP_GTTR_MAX_LINES).y
|
||||
|
||||
var adj_h: float = POPUP_LINE_H # minimum one line
|
||||
if not adj_line.is_empty():
|
||||
adj_h = font.get_multiline_string_size(
|
||||
adj_line, HORIZONTAL_ALIGNMENT_LEFT, inner_w, 10, 3).y
|
||||
|
||||
# ── Calculate total panel height ─────────────────────────────────────────
|
||||
var panel_h: float = pad # top padding
|
||||
panel_h += POPUP_LINE_H # system name (15px font)
|
||||
panel_h += POPUP_LINE_H # system id (10px font)
|
||||
panel_h += sep_h # separator
|
||||
panel_h += POPUP_LINE_H # star type + hop
|
||||
panel_h += POPUP_LINE_H # corridor
|
||||
panel_h += POPUP_LINE_H # bodies + pop
|
||||
if not gttr.is_empty():
|
||||
panel_h += sep_h + gttr_h
|
||||
panel_h += sep_h + adj_h # adjacent systems
|
||||
panel_h += pad # bottom padding
|
||||
|
||||
# ── Draw background ──────────────────────────────────────────────────────
|
||||
var panel_pos := Vector2(sz.x - panel_w - POPUP_MARGIN, POPUP_MARGIN)
|
||||
var x: float = panel_pos.x + pad
|
||||
var x_right: float = panel_pos.x + panel_w - pad
|
||||
var y: float = panel_pos.y + pad + POPUP_LINE_H # baseline offset
|
||||
|
||||
draw_rect(Rect2(panel_pos, Vector2(panel_w, panel_h)), COLOR_INFO_BG)
|
||||
draw_rect(Rect2(panel_pos, Vector2(panel_w, panel_h)), sep_color, false, 1.0)
|
||||
|
||||
# ── Draw content ─────────────────────────────────────────────────────────
|
||||
|
||||
# System name
|
||||
draw_string(font, Vector2(x, y), sys_name,
|
||||
HORIZONTAL_ALIGNMENT_LEFT, inner_w, 15, COLOR_TEXT)
|
||||
y += POPUP_LINE_H
|
||||
|
||||
# System ID
|
||||
draw_string(font, Vector2(x, y), node.get("system_id", ""),
|
||||
HORIZONTAL_ALIGNMENT_LEFT, inner_w, 10, COLOR_TEXT_DIM)
|
||||
y += POPUP_LINE_H
|
||||
|
||||
# Separator
|
||||
draw_line(Vector2(x, y + 2.0), Vector2(x_right, y + 2.0), sep_color, 1.0)
|
||||
y += sep_h
|
||||
|
||||
# Star type + hop
|
||||
draw_string(font, Vector2(x, y), stat_line_1,
|
||||
HORIZONTAL_ALIGNMENT_LEFT, inner_w, 11, COLOR_TEXT_DIM)
|
||||
y += POPUP_LINE_H
|
||||
|
||||
# Corridor
|
||||
draw_string(font, Vector2(x, y), sector_str + " corridor",
|
||||
HORIZONTAL_ALIGNMENT_LEFT, inner_w, 11, sector_color)
|
||||
y += POPUP_LINE_H
|
||||
|
||||
# Bodies + population
|
||||
draw_string(font, Vector2(x, y), stat_line_3,
|
||||
HORIZONTAL_ALIGNMENT_LEFT, inner_w, 11, COLOR_TEXT_DIM)
|
||||
y += POPUP_LINE_H
|
||||
|
||||
# GTTR excerpt
|
||||
if not gttr.is_empty():
|
||||
draw_line(Vector2(x, y + 2.0), Vector2(x_right, y + 2.0), sep_color, 1.0)
|
||||
y += sep_h
|
||||
draw_multiline_string(font, Vector2(x, y), gttr,
|
||||
HORIZONTAL_ALIGNMENT_LEFT, inner_w, POPUP_GTTR_FONT_SIZE,
|
||||
POPUP_GTTR_MAX_LINES,
|
||||
Color(COLOR_TEXT.r, COLOR_TEXT.g, COLOR_TEXT.b, 0.75))
|
||||
y += gttr_h
|
||||
|
||||
# Adjacent systems
|
||||
draw_line(Vector2(x, y + 2.0), Vector2(x_right, y + 2.0), sep_color, 1.0)
|
||||
y += sep_h
|
||||
if adj_line.is_empty():
|
||||
draw_string(font, Vector2(x, y), "No gate connections",
|
||||
HORIZONTAL_ALIGNMENT_LEFT, inner_w, 10, COLOR_TEXT_DIM)
|
||||
else:
|
||||
draw_multiline_string(font, Vector2(x, y), adj_line,
|
||||
HORIZONTAL_ALIGNMENT_LEFT, inner_w, 10, 3, COLOR_TEXT_DIM)
|
||||
|
||||
|
||||
func _draw_title() -> void:
|
||||
|
||||
Reference in New Issue
Block a user