diff options
Diffstat (limited to 'src/LivingVillage.Desktop/Interaction.fs')
| -rw-r--r-- | src/LivingVillage.Desktop/Interaction.fs | 53 |
1 files changed, 53 insertions, 0 deletions
diff --git a/src/LivingVillage.Desktop/Interaction.fs b/src/LivingVillage.Desktop/Interaction.fs index 3a65e8e..5281180 100644 --- a/src/LivingVillage.Desktop/Interaction.fs +++ b/src/LivingVillage.Desktop/Interaction.fs @@ -211,6 +211,59 @@ module FloatingPrompt = let y = max topSafe (min bottomSafe screenY) { X = x; Y = y; Width = width; Height = height } + /// P77:锚定提示支持长文本折行(逐字、不丢字),供真实用例(如「E 与河边的货郎交谈并查看货品」)。 + let maxPromptWidth = 360 + + type PromptLayout = + { Lines: string list + X: int + Y: int + Width: int + Height: int } + + let wrapText (maxWidth: int) (scale: int) (text: string) : string list = + if text = "" then + [ "" ] + else + let builder = System.Text.StringBuilder() + let mutable lines = [] + for ch in text.ToCharArray() do + let candidate = builder.ToString() + string ch + if builder.Length > 0 && measureWidth candidate scale > maxWidth then + lines <- builder.ToString() :: lines + builder.Clear() |> ignore + builder.Append(ch) |> ignore + else + builder.Append(ch) |> ignore + lines <- builder.ToString() :: lines + List.rev lines + + /// 锚定点的多行提示版式:按需折行、水平居中于目标、垂直钳制在两条 HUD 带之间。 + let layoutWrapped + (viewportWidth: int) + (viewportHeight: int) + (anchorWorldX: float32) + (anchorWorldY: float32) + (cameraX: float32) + (cameraY: float32) + (scale: int) + (text: string) : PromptLayout = + let margin = 8 + let wrapWidth = min maxPromptWidth (max 80 (viewportWidth - 2 * margin)) + let lines = wrapText wrapWidth scale text + let width = lines |> List.map (fun line -> measureWidth line scale) |> List.max + let lineHeight = 8 * scale + 4 + let height = lines.Length * lineHeight + 10 + let screenX = int anchorWorldX - int cameraX - width / 2 + let screenY = int anchorWorldY - int cameraY - 24 - height + let x = + if width + margin * 2 > viewportWidth then margin + else max margin (min (viewportWidth - margin - width) screenX) + let topSafe = hudTopBarHeight + margin + let bottomSafe = max topSafe (viewportHeight - hudBottomBandHeight - height - margin) + let y = max topSafe (min bottomSafe screenY) + { Lines = lines; X = x; Y = y; Width = width; Height = height } + module M5Interaction = let initial : M5View = |
