From 5f6b8c993aa9ea0d1933931c6aff2ec157fc1989 Mon Sep 17 00:00:00 2001 From: Dmitry Stepanov Date: Sat, 26 Sep 2026 22:50:26 +0300 Subject: [PATCH] use text inline widgets in markdown --- fyrox-ui/src/markdown.rs | 120 ++++++++++++++++++++++----------------- 1 file changed, 67 insertions(+), 53 deletions(-) diff --git a/fyrox-ui/src/markdown.rs b/fyrox-ui/src/markdown.rs index 2c8506ad7..94ba011e4 100644 --- a/fyrox-ui/src/markdown.rs +++ b/fyrox-ui/src/markdown.rs @@ -18,7 +18,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -use crate::wrap_panel::WrapPanelBuilder; +use crate::text::TextMessage; use crate::{ border::BorderBuilder, core::{err, pool::Handle}, @@ -26,8 +26,8 @@ use crate::{ stack_panel::StackPanelBuilder, style::{resource::StyleResourceExt, Style}, text::TextBuilder, - widget::WidgetBuilder, - BuildContext, Orientation, Thickness, UiNode, UserInterface, + widget::{WidgetBuilder, WidgetMessage}, + BuildContext, Thickness, UiNode, UserInterface, VerticalAlignment, }; fn heading_depth_to_font_size(heading_depth: u8) -> f32 { @@ -72,62 +72,76 @@ pub fn markdown_to_visual_tree(ui: &mut UserInterface, text: impl AsRef) -> heading_depth: &mut u8, ui: &mut UserInterface, ) -> Handle { - let mut widget_builder = WidgetBuilder::new(); - let prev_heading_depth = *heading_depth; match ast_node { - Node::Paragraph(_) => { - widget_builder = widget_builder.with_margin(Thickness::top(16.0)); - } - Node::Heading(heading) => { - *heading_depth = heading.depth; - } - _ => (), - } + Node::Paragraph(paragraph) => { + let paragraph_text = + TextBuilder::new(WidgetBuilder::new().with_margin(Thickness::top(16.0))) + .with_font_size(heading_depth_to_font_size(*heading_depth).into()) + .with_wrap(WrapMode::Word) + .build(&mut ui.build_ctx()) + .to_base(); - if let Some(children) = ast_node.children() { - for child_ast_node in children { - let child_widget = traverse_ast_recursively(child_ast_node, heading_depth, ui); - widget_builder = widget_builder.with_child(child_widget); + let mut full_text = String::new(); + + for child_ast_node in paragraph.children.iter() { + if let Node::Text(text) = child_ast_node { + full_text.push_str(&text.value); + } else { + let child_widget = + traverse_ast_recursively(child_ast_node, heading_depth, ui); + let child_widget_ref = &mut ui[child_widget]; + child_widget_ref.set_column(full_text.chars().count().saturating_sub(1)); + child_widget_ref.set_vertical_alignment(VerticalAlignment::Center); + ui.send(child_widget, WidgetMessage::LinkWith(paragraph_text)); + } + } + + ui.send(paragraph_text, TextMessage::Text(full_text)); + + paragraph_text + } + ast_node => { + if let Node::Heading(heading) = ast_node { + *heading_depth = heading.depth; + } + + let mut widget_builder = WidgetBuilder::new(); + + if let Some(children) = ast_node.children() { + for child_ast_node in children { + let child_widget = + traverse_ast_recursively(child_ast_node, heading_depth, ui); + widget_builder = widget_builder.with_child(child_widget); + } + } + + *heading_depth = prev_heading_depth; + + let ctx = &mut ui.build_ctx(); + + match ast_node { + Node::InlineCode(inline_code) => make_text_with_border( + widget_builder, + *heading_depth, + &inline_code.value, + WrapMode::NoWrap, + ctx, + ), + Node::Code(code) => make_text_with_border( + widget_builder, + *heading_depth, + &code.value, + WrapMode::Word, + ctx, + ), + _ => StackPanelBuilder::new(widget_builder) + .build(ctx) + .to_base::(), + } } } - - *heading_depth = prev_heading_depth; - - let ctx = &mut ui.build_ctx(); - - let widget = match ast_node { - Node::Text(text) => TextBuilder::new(widget_builder) - .with_text(&text.value) - .with_font_size(heading_depth_to_font_size(*heading_depth).into()) - .with_wrap(WrapMode::Word) - .build(ctx) - .to_base(), - Node::InlineCode(inline_code) => make_text_with_border( - widget_builder, - *heading_depth, - &inline_code.value, - WrapMode::NoWrap, - ctx, - ), - Node::Code(code) => make_text_with_border( - widget_builder, - *heading_depth, - &code.value, - WrapMode::Word, - ctx, - ), - Node::Paragraph(_) => WrapPanelBuilder::new(widget_builder) - .with_orientation(Orientation::Horizontal) - .build(ctx) - .to_base(), - _ => StackPanelBuilder::new(widget_builder) - .build(ctx) - .to_base::(), - }; - - widget } let text = text.as_ref();