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
24 .calculate_visual_lines(&self.buffer, self.viewport_width);
25
26 let total_visual_lines = visual_lines.len();
27 let content_height = total_visual_lines as f32 * LINE_HEIGHT;
28
29 let canvas_height = content_height.max(self.viewport_height);
33
34 let canvas = Canvas::new(self)
36 .width(Length::Fill)
37 .height(Length::Fixed(canvas_height));
38
39 let scrollbar_bg = self.style.scrollbar_background;
41 let scroller_color = self.style.scroller_color;
42 let background_color = self.style.background;
43 let gutter_background = self.style.gutter_background;
44
45 let scrollable = Scrollable::new(canvas)
49 .id(self.scrollable_id.clone())
50 .width(Length::Fill)
51 .height(Length::Fill)
52 .on_scroll(Message::Scrolled)
53 .style(move |_theme, _status| scrollable::Style {
54 container: container::Style {
55 background: Some(Background::Color(Color::TRANSPARENT)),
56 ..container::Style::default()
57 },
58 vertical_rail: scrollable::Rail {
59 background: Some(scrollbar_bg.into()),
60 border: Border {
61 radius: 4.0.into(),
62 width: 0.0,
63 color: Color::TRANSPARENT,
64 },
65 scroller: scrollable::Scroller {
66 background: scroller_color.into(),
67 border: Border {
68 radius: 4.0.into(),
69 width: 0.0,
70 color: Color::TRANSPARENT,
71 },
72 },
73 },
74 horizontal_rail: scrollable::Rail {
75 background: Some(scrollbar_bg.into()),
76 border: Border {
77 radius: 4.0.into(),
78 width: 0.0,
79 color: Color::TRANSPARENT,
80 },
81 scroller: scrollable::Scroller {
82 background: scroller_color.into(),
83 border: Border {
84 radius: 4.0.into(),
85 width: 0.0,
86 color: Color::TRANSPARENT,
87 },
88 },
89 },
90 gap: None,
91 auto_scroll: scrollable::AutoScroll {
92 background: Color::TRANSPARENT.into(),
93 border: Border::default(),
94 shadow: Shadow::default(),
95 icon: Color::TRANSPARENT,
96 },
97 });
98
99 let gutter_container =
101 container(Space::new().width(Length::Fill).height(Length::Fill))
102 .width(Length::Fixed(GUTTER_WIDTH))
103 .height(Length::Fill)
104 .style(move |_| container::Style {
105 background: Some(Background::Color(gutter_background)),
106 ..container::Style::default()
107 });
108
109 let code_background_container =
111 container(Space::new().width(Length::Fill).height(Length::Fill))
112 .width(Length::Fill)
113 .height(Length::Fill)
114 .style(move |_| container::Style {
115 background: Some(Background::Color(background_color)),
116 ..container::Style::default()
117 });
118
119 let mut editor_stack = iced::widget::Stack::new()
122 .push(
123 Row::new()
125 .push(gutter_container)
126 .push(code_background_container),
127 )
128 .push(
129 scrollable,
131 );
132
133 if self.search_state.is_open {
135 let search_dialog =
136 search_dialog::view(&self.search_state, &self.translations);
137
138 let positioned_dialog = container(
141 Row::new()
142 .push(Space::new().width(Length::Fill)) .push(search_dialog),
144 )
145 .padding(20) .width(Length::Fill)
147 .height(Length::Shrink);
148
149 editor_stack = editor_stack.push(positioned_dialog);
150 }
151
152 container(editor_stack)
154 .width(Length::Fill)
155 .height(Length::Fill)
156 .clip(true)
157 .into()
158 }
159}