fresh/app/
view_actions.rs1use super::Editor;
6use crate::model::event::LeafId;
7use crate::state::ViewMode;
8use rust_i18n::t;
9
10impl Editor {
11 pub fn handle_toggle_page_view(&mut self) {
13 let active_split = self.split_manager.active_split();
14 let active_buffer = self
15 .split_manager
16 .get_buffer_id(active_split.into())
17 .unwrap_or(crate::model::event::BufferId(0));
18 let default_wrap = self.resolve_line_wrap_for_buffer(active_buffer);
19 let default_line_numbers = self.config.editor.line_numbers;
20 let page_width = self
21 .buffers
22 .get(&active_buffer)
23 .and_then(|s| self.config.languages.get(&s.language))
24 .and_then(|lc| lc.page_width)
25 .or(self.config.editor.page_width);
26
27 let view_mode = {
28 let current = self
29 .split_view_states
30 .get(&active_split)
31 .map(|vs| vs.view_mode.clone())
32 .unwrap_or(ViewMode::Source);
33 match current {
34 ViewMode::PageView => ViewMode::Source,
35 _ => ViewMode::PageView,
36 }
37 };
38
39 if let Some(vs) = self.split_view_states.get_mut(&active_split) {
41 vs.view_mode = view_mode.clone();
42 vs.viewport.line_wrap_enabled = match view_mode {
46 ViewMode::PageView => false,
47 ViewMode::Source => default_wrap,
48 };
49 match view_mode {
50 ViewMode::PageView => {
51 vs.show_line_numbers = false;
52 if let Some(width) = page_width {
54 vs.compose_width = Some(width as u16);
55 }
56 }
57 ViewMode::Source => {
58 vs.compose_width = None;
60 vs.view_transform = None;
61 vs.show_line_numbers = default_line_numbers;
62 }
63 }
64 }
65
66 let mode_label = match view_mode {
67 ViewMode::PageView => t!("view.page_view").to_string(),
68 ViewMode::Source => "Source".to_string(),
69 };
70 self.set_status_message(t!("view.mode", mode = mode_label).to_string());
71 }
72
73 pub(crate) fn animate_tab_switch(&mut self, split_id: LeafId, direction: i32) {
84 if direction == 0 {
85 return;
86 }
87 if !self.config.editor.animations {
88 return;
89 }
90 let Some(area) = self.split_or_group_content_rect(split_id) else {
91 return;
92 };
93 if area.width == 0 || area.height == 0 {
94 return;
95 }
96 let from = if direction > 0 {
97 crate::view::animation::Edge::Right
98 } else {
99 crate::view::animation::Edge::Left
100 };
101 self.animations.start(
102 area,
103 crate::view::animation::AnimationKind::SlideIn {
104 from,
105 duration: std::time::Duration::from_millis(260),
106 delay: std::time::Duration::ZERO,
107 },
108 );
109 }
110
111 fn split_or_group_content_rect(&self, split_id: LeafId) -> Option<ratatui::layout::Rect> {
124 if let Some(rect) = self
125 .cached_layout
126 .split_areas
127 .iter()
128 .find(|(sid, _, _, _, _, _)| *sid == split_id)
129 .map(|(_, _, content_rect, _, _, _)| *content_rect)
130 {
131 return Some(rect);
132 }
133
134 let group_leaf = self
138 .split_view_states
139 .get(&split_id)
140 .and_then(|vs| vs.active_group_tab)?;
141 let subtree = self.grouped_subtrees.get(&group_leaf)?;
142
143 let mut inner_leaves: Vec<LeafId> = Vec::new();
144 collect_leaf_ids(subtree, &mut inner_leaves);
145
146 let mut union: Option<ratatui::layout::Rect> = None;
147 for (sid, _, content, _, _, _) in &self.cached_layout.split_areas {
148 if !inner_leaves.contains(sid) {
149 continue;
150 }
151 union = Some(match union {
152 None => *content,
153 Some(prev) => rect_union(prev, *content),
154 });
155 }
156 union
157 }
158}
159
160fn collect_leaf_ids(node: &crate::view::split::SplitNode, out: &mut Vec<LeafId>) {
162 use crate::view::split::SplitNode;
163 match node {
164 SplitNode::Leaf { split_id, .. } => out.push(*split_id),
165 SplitNode::Split { first, second, .. } => {
166 collect_leaf_ids(first, out);
167 collect_leaf_ids(second, out);
168 }
169 SplitNode::Grouped { layout, .. } => collect_leaf_ids(layout, out),
170 }
171}
172
173fn rect_union(a: ratatui::layout::Rect, b: ratatui::layout::Rect) -> ratatui::layout::Rect {
174 let x = a.x.min(b.x);
175 let y = a.y.min(b.y);
176 let right = a.x.saturating_add(a.width).max(b.x.saturating_add(b.width));
177 let bottom =
178 a.y.saturating_add(a.height)
179 .max(b.y.saturating_add(b.height));
180 ratatui::layout::Rect::new(x, y, right.saturating_sub(x), bottom.saturating_sub(y))
181}