ratatui_toolkit/widgets/markdown_widget/widget/methods/sync_state_back.rs
1//! Sync widget state back to MarkdownState.
2
3use crate::widgets::markdown_widget::state::MarkdownState;
4use crate::widgets::markdown_widget::widget::MarkdownWidget;
5
6/// State captured from MarkdownWidget that needs to be synced back to MarkdownState.
7///
8/// This struct holds the values that the widget may modify during event handling
9/// that need to persist back to the application state.
10#[derive(Debug, Clone)]
11pub struct WidgetStateSync {
12 /// Whether the TOC is currently hovered.
13 pub toc_hovered: bool,
14 /// Index of the hovered TOC entry.
15 pub toc_hovered_entry: Option<usize>,
16 /// Scroll offset for the TOC list.
17 pub toc_scroll_offset: usize,
18 /// Whether selection mode is active.
19 pub selection_active: bool,
20 /// Last double-click info (line number, kind, content).
21 pub last_double_click: Option<(usize, String, String)>,
22 /// Current filter text (when in filter mode).
23 pub filter: Option<String>,
24 /// Whether filter mode is currently active.
25 pub filter_mode: bool,
26}
27
28impl WidgetStateSync {
29 /// Apply this sync state to a MarkdownState.
30 ///
31 /// # Arguments
32 ///
33 /// * `state` - The MarkdownState to sync state to
34 pub fn apply_to(&self, state: &mut MarkdownState) {
35 state.toc_hovered = self.toc_hovered;
36 state.toc_hovered_entry = self.toc_hovered_entry;
37 state.toc_scroll_offset = self.toc_scroll_offset;
38 state.selection_active = self.selection_active;
39 state.filter = self.filter.clone();
40 state.filter_mode = self.filter_mode;
41 }
42
43 /// Check if there was a double-click and consume it.
44 pub fn take_double_click(&mut self) -> Option<(usize, String, String)> {
45 self.last_double_click.take()
46 }
47}
48
49impl<'a> MarkdownWidget<'a> {
50 /// Get the state that needs to be synced back to MarkdownState.
51 ///
52 /// This method captures the TOC and selection state from the widget
53 /// so it can be synced back after the widget is dropped.
54 ///
55 /// # Returns
56 ///
57 /// A `WidgetStateSync` struct containing the state values to sync.
58 ///
59 /// # Example
60 ///
61 /// ```rust,ignore
62 /// let sync_state = {
63 /// let mut widget = MarkdownWidget::from_state(&content, &mut state).show_toc(true);
64 /// widget.handle_toc_hover(&mouse, render_area);
65 /// widget.handle_toc_click(&mouse, render_area);
66 /// widget.handle_mouse_event(&mouse, render_area);
67 /// widget.get_state_sync()
68 /// };
69 /// sync_state.apply_to(&mut state);
70 /// ```
71 pub fn get_state_sync(&mut self) -> WidgetStateSync {
72 WidgetStateSync {
73 toc_hovered: self.toc_hovered,
74 toc_hovered_entry: self.toc_hovered_entry,
75 toc_scroll_offset: self.toc_scroll_offset,
76 selection_active: self.selection.is_active(),
77 last_double_click: self.last_double_click.take(),
78 filter: self.filter.clone(),
79 filter_mode: self.filter_mode,
80 }
81 }
82
83 /// Sync widget state back to MarkdownState by consuming self.
84 ///
85 /// This method consumes the widget and syncs TOC and selection state back to
86 /// the MarkdownState, ensuring state persistence between frames.
87 ///
88 /// Call this after handling mouse events to preserve hover and selection state.
89 ///
90 /// # Arguments
91 ///
92 /// * `state` - The MarkdownState to sync state back to
93 ///
94 /// # Example
95 ///
96 /// ```rust,ignore
97 /// let mut widget = MarkdownWidget::from_state(&content, &mut state).show_toc(true);
98 /// widget.handle_toc_hover(&mouse, render_area);
99 /// widget.handle_toc_click(&mouse, render_area);
100 /// widget.handle_mouse_event(&mouse, render_area);
101 /// widget.sync_state_back(&mut state);
102 /// ```
103 pub fn sync_state_back(self, state: &mut MarkdownState) {
104 state.toc_hovered = self.toc_hovered;
105 state.toc_hovered_entry = self.toc_hovered_entry;
106 state.toc_scroll_offset = self.toc_scroll_offset;
107 state.selection_active = self.selection.is_active();
108 state.filter = self.filter;
109 state.filter_mode = self.filter_mode;
110 }
111}