|
6 | 6 | //! |
7 | 7 | //! 数据模型见 [`crate::chat::ChatHistory`];UI 层仅做渲染与输入捕获,不负责发送 / 持久化。 |
8 | 8 |
|
| 9 | +use std::borrow::Cow; |
| 10 | + |
9 | 11 | use crate::chat::{ChatHistory, ChatKind}; |
10 | 12 |
|
| 13 | +/// 聊天 UI 只按单行展示消息:自动换行由 Label 配置禁止,显式 CR/LF 也在显示层折成空格。 |
| 14 | +fn single_line_text(text: &str) -> Cow<'_, str> { |
| 15 | + if text.contains('\n') || text.contains('\r') { |
| 16 | + Cow::Owned( |
| 17 | + text.chars() |
| 18 | + .map(|c| if matches!(c, '\n' | '\r') { ' ' } else { c }) |
| 19 | + .collect(), |
| 20 | + ) |
| 21 | + } else { |
| 22 | + Cow::Borrowed(text) |
| 23 | + } |
| 24 | +} |
| 25 | + |
11 | 26 | /// 聊天 UI 单帧返回的动作。 |
12 | 27 | #[derive(Clone, Debug, PartialEq, Eq)] |
13 | 28 | pub enum ChatUiAction { |
@@ -45,22 +60,36 @@ pub fn draw_chat_window(ctx: &egui::Context, history: &mut ChatHistory) -> ChatU |
45 | 60 | .stick_to_bottom(true) |
46 | 61 | .show(ui, |ui| { |
47 | 62 | for msg in history.recent(50) { |
48 | | - ui.horizontal_wrapped(|ui| match &msg.kind { |
| 63 | + // 一条聊天消息固定占一行;正文用 Extend 禁止自动换行, |
| 64 | + // 避免玩家名和消息内容在宽度边界附近被拆到两行。 |
| 65 | + ui.horizontal(|ui| match &msg.kind { |
49 | 66 | ChatKind::System => { |
50 | | - ui.colored_label( |
51 | | - egui::Color32::from_rgb(160, 170, 180), |
52 | | - format!("[System] {}", msg.content), |
| 67 | + let content = single_line_text(&msg.content); |
| 68 | + ui.add( |
| 69 | + egui::Label::new( |
| 70 | + egui::RichText::new(format!("[System] {content}")) |
| 71 | + .color(egui::Color32::from_rgb(160, 170, 180)), |
| 72 | + ) |
| 73 | + .wrap_mode(egui::TextWrapMode::Extend), |
53 | 74 | ); |
54 | 75 | } |
55 | 76 | ChatKind::User { from_name, .. } => { |
56 | | - ui.label( |
57 | | - egui::RichText::new(format!("{from_name}: ")) |
58 | | - .strong() |
59 | | - .color(egui::Color32::from_rgb(220, 230, 240)), |
| 77 | + let from_name = single_line_text(from_name); |
| 78 | + let content = single_line_text(&msg.content); |
| 79 | + ui.add( |
| 80 | + egui::Label::new( |
| 81 | + egui::RichText::new(format!("{from_name}: ")) |
| 82 | + .strong() |
| 83 | + .color(egui::Color32::from_rgb(220, 230, 240)), |
| 84 | + ) |
| 85 | + .wrap_mode(egui::TextWrapMode::Extend), |
60 | 86 | ); |
61 | | - ui.label( |
62 | | - egui::RichText::new(&msg.content) |
63 | | - .color(egui::Color32::from_rgb(230, 235, 240)), |
| 87 | + ui.add( |
| 88 | + egui::Label::new( |
| 89 | + egui::RichText::new(content.as_ref()) |
| 90 | + .color(egui::Color32::from_rgb(230, 235, 240)), |
| 91 | + ) |
| 92 | + .wrap_mode(egui::TextWrapMode::Extend), |
64 | 93 | ); |
65 | 94 | } |
66 | 95 | }); |
@@ -125,23 +154,37 @@ pub fn draw_recent_overlay(ctx: &egui::Context, history: &ChatHistory, now_ms: f |
125 | 154 | ChatKind::System => { |
126 | 155 | // 系统消息:淡灰色。 |
127 | 156 | let color = egui::Color32::from_rgba_unmultiplied(170, 180, 195, alpha); |
128 | | - ui.label( |
129 | | - egui::RichText::new(format!("[System] {}", msg.content)).color(color), |
| 157 | + let content = single_line_text(&msg.content); |
| 158 | + ui.add( |
| 159 | + egui::Label::new( |
| 160 | + egui::RichText::new(format!("[System] {content}")).color(color), |
| 161 | + ) |
| 162 | + .wrap_mode(egui::TextWrapMode::Extend), |
130 | 163 | ); |
131 | 164 | } |
132 | 165 | ChatKind::User { from_name, .. } => { |
133 | 166 | // 用户消息:发送者加粗稍亮 + 内容白底。 |
| 167 | + let from_name = single_line_text(from_name); |
| 168 | + let content = single_line_text(&msg.content); |
134 | 169 | let name_color = |
135 | 170 | egui::Color32::from_rgba_unmultiplied(235, 215, 130, alpha); |
136 | 171 | let body_color = |
137 | 172 | egui::Color32::from_rgba_unmultiplied(240, 240, 240, alpha); |
138 | | - ui.horizontal_wrapped(|ui| { |
139 | | - ui.label( |
140 | | - egui::RichText::new(format!("{from_name}: ")) |
141 | | - .strong() |
142 | | - .color(name_color), |
| 173 | + ui.horizontal(|ui| { |
| 174 | + ui.add( |
| 175 | + egui::Label::new( |
| 176 | + egui::RichText::new(format!("{from_name}: ")) |
| 177 | + .strong() |
| 178 | + .color(name_color), |
| 179 | + ) |
| 180 | + .wrap_mode(egui::TextWrapMode::Extend), |
| 181 | + ); |
| 182 | + ui.add( |
| 183 | + egui::Label::new( |
| 184 | + egui::RichText::new(content.as_ref()).color(body_color), |
| 185 | + ) |
| 186 | + .wrap_mode(egui::TextWrapMode::Extend), |
143 | 187 | ); |
144 | | - ui.label(egui::RichText::new(&msg.content).color(body_color)); |
145 | 188 | }); |
146 | 189 | } |
147 | 190 | } |
|
0 commit comments