iced_code_editor/canvas_editor/
view.rs1use iced::widget::canvas::Canvas;
4use iced::widget::{Row, Scrollable, Space, container, scrollable};
5use iced::{Background, Border, Color, Element, Length, Shadow};
6
7use super::search_dialog;
8use super::wrapping::WrappingCalculator;
9use super::{CodeEditor, GUTTER_WIDTH, LINE_HEIGHT, Message};
10
11impl CodeEditor {
12 pub fn view(&self) -> Element<'_, Message> {
17 let wrapping_calc =
20 WrappingCalculator::new(self.wrap_enabled, self.wrap_column);
21
22 let visual_lines = wrapping_calc.calculate_visual_lines(
24 &self.buffer,
25 self.viewport_width,
26 self.gutter_width(),
27 );
28
29 let total_visual_lines = visual_lines.len();
30 let content_height = total_visual_lines as f32 * LINE_HEIGHT;
31
32 let canvas_height = content_height.max(self.viewport_height);
36
37 let canvas = Canvas::new(self)
39 .width(Length::Fill)
40 .height(Length::Fixed(canvas_height));
41
42 let scrollbar_bg = self.style.scrollbar_background;
44 let scroller_color = self.style.scroller_color;
45 let background_color = self.style.background;
46 let gutter_background = self.style.gutter_background;
47
48 let scrollable = Scrollable::new(canvas)
52 .id(self.scrollable_id.clone())
53 .width(Length::Fill)
54 .height(Length::Fill)
55 .on_scroll(Message::Scrolled)
56 .style(move |_theme, _status| scrollable::Style {
57 container: container::Style {
58 background: Some(Background::Color(Color::TRANSPARENT)),
59 ..container::Style::default()
60 },
61 vertical_rail: scrollable::Rail {
62 background: Some(scrollbar_bg.into()),
63 border: Border {
64 radius: 4.0.into(),
65 width: 0.0,
66 color: Color::TRANSPARENT,
67 },
68 scroller: scrollable::Scroller {
69 background: scroller_color.into(),
70 border: Border {
71 radius: 4.0.into(),
72 width: 0.0,
73 color: Color::TRANSPARENT,
74 },
75 },
76 },
77 horizontal_rail: scrollable::Rail {
78 background: Some(scrollbar_bg.into()),
79 border: Border {
80 radius: 4.0.into(),
81 width: 0.0,
82 color: Color::TRANSPARENT,
83 },
84 scroller: scrollable::Scroller {
85 background: scroller_color.into(),
86 border: Border {
87 radius: 4.0.into(),
88 width: 0.0,
89 color: Color::TRANSPARENT,
90 },
91 },
92 },
93 gap: None,
94 auto_scroll: scrollable::AutoScroll {
95 background: Color::TRANSPARENT.into(),
96 border: Border::default(),
97 shadow: Shadow::default(),
98 icon: Color::TRANSPARENT,
99 },
100 });
101
102 let gutter_container = if self.line_numbers_enabled {
105 Some(
106 container(
107 Space::new().width(Length::Fill).height(Length::Fill),
108 )
109 .width(Length::Fixed(GUTTER_WIDTH))
110 .height(Length::Fill)
111 .style(move |_| container::Style {
112 background: Some(Background::Color(gutter_background)),
113 ..container::Style::default()
114 }),
115 )
116 } else {
117 None
118 };
119
120 let code_background_container =
122 container(Space::new().width(Length::Fill).height(Length::Fill))
123 .width(Length::Fill)
124 .height(Length::Fill)
125 .style(move |_| container::Style {
126 background: Some(Background::Color(background_color)),
127 ..container::Style::default()
128 });
129
130 let background_row = if let Some(gutter) = gutter_container {
133 Row::new().push(gutter).push(code_background_container)
134 } else {
135 Row::new().push(code_background_container)
136 };
137
138 let mut editor_stack = iced::widget::Stack::new()
139 .push(
140 background_row,
142 )
143 .push(
144 scrollable,
146 );
147
148 if self.search_state.is_open {
150 let search_dialog =
151 search_dialog::view(&self.search_state, &self.translations);
152
153 let positioned_dialog = container(
156 Row::new()
157 .push(Space::new().width(Length::Fill)) .push(search_dialog),
159 )
160 .padding(20) .width(Length::Fill)
162 .height(Length::Shrink);
163
164 editor_stack = editor_stack.push(positioned_dialog);
165 }
166
167 container(editor_stack)
169 .width(Length::Fill)
170 .height(Length::Fill)
171 .clip(true)
172 .into()
173 }
174}