1use makepad_render::*;
2use crate::scrollview::*;
3use crate::textbuffer::*;
4use crate::textcursor::*;
5use crate::widgetstyle::*;
6use crate::scrollshadow::*;
7
8#[derive(Clone)]
9pub struct TextEditor {
10 pub view: ScrollView,
11 pub view_layout: Layout,
12 pub bg: Quad,
13 pub gutter_bg: Quad,
14 pub cursor: Quad,
15 pub selection: Quad,
16 pub token_highlight: Quad,
17 pub cursor_row: Quad,
19 pub paren_pair: Quad,
20 pub indent_lines: Quad,
21 pub shadow: ScrollShadow,
22 pub message_marker: Quad,
23 pub text: Text,
24 pub line_number_text: Text,
25 pub cursors: TextCursorSet,
26
27 pub open_font_scale: f32,
29 pub folded_font_scale: f32,
30 pub line_number_width: f32,
31 pub line_number_click_margin: f32,
32 pub draw_line_numbers: bool,
33 pub top_padding: f32,
34 pub cursor_blink_speed: f64,
36 pub _undo_id: u64,
37 pub highlight_area_on: bool,
38
39 pub mark_unmatched_parens: bool,
40 pub draw_cursor_row: bool,
41 pub folding_depth: usize,
42 pub colors: CodeEditorColors,
43
44 pub read_only: bool,
45 pub multiline: bool,
46
47 pub _scroll_pos_on_load: Option<Vec2>,
49 pub _jump_to_offset: bool,
50 pub _view_area: Area,
51 pub _highlight_area: Area,
52 pub _text_inst: Option<AlignedInstance>,
53 pub _line_number_inst: Option<AlignedInstance>,
54 pub _line_number_chunk: Vec<char>,
55 pub _text_area: Area,
56 pub _scroll_pos: Vec2,
57 pub _last_finger_move: Option<Vec2>,
58 pub _paren_stack: Vec<ParenItem>,
59 pub _indent_stack: Vec<(Color, f32)>,
60 pub _indent_id_alloc: f32,
61 pub _indent_line_inst: Option<InstanceArea>,
62 pub _bg_inst: Option<InstanceArea>,
63 pub _last_indent_color: Color,
64
65 pub _line_geometry: Vec<LineGeom>,
66 pub _anim_select: Vec<AnimSelect>,
67 pub _visible_lines: usize,
68
69 pub _select_scroll: Option<SelectScroll>,
70 pub _grid_select_corner: Option<TextPos>,
71 pub _is_row_select: bool,
72 pub _line_chunk: Vec<(f32, char)>,
73
74 pub _highlight_selection: Vec<char>,
75 pub _highlight_token: Vec<char>,
76 pub _last_cursor_pos: TextPos,
77
78 pub _anim_font_scale: f32,
79 pub _line_largest_font: f32,
80 pub _anim_folding: AnimFolding,
81
82 pub _monospace_size: Vec2,
83 pub _monospace_base: Vec2,
84
85 pub _tokens_on_line: usize,
86 pub _line_was_folded: bool,
87 pub _final_fill_height: f32,
89 pub _draw_cursors: DrawCursors,
90 pub _draw_search: DrawCursors,
91 pub _draw_messages: DrawCursors,
92
93 pub _cursor_blink_timer: Timer,
94 pub _cursor_blink_flipflop: f32,
95 pub _cursor_area: Area,
96 pub _highlight_visibility: f32,
97
98 pub _last_tabs: usize,
99 pub _newline_tabs: usize,
100
101 pub _jump_to_offset_id: u64,
102
103 pub _last_lag_mutation_id: u64
104}
105
106#[derive(Clone, PartialEq)]
107pub enum TextEditorEvent {
108 None,
109 AutoFormat,
110 LagChange,
111 Change
112}
113
114#[derive(Default, Clone)]
115pub struct CodeEditorColors {
116 indent_line_unknown: Color,
117 indent_line_fn: Color,
118 indent_line_typedef: Color,
119 indent_line_looping: Color,
120 indent_line_flow: Color,
121 paren_pair_match: Color,
122 paren_pair_fail: Color,
123 marker_error: Color,
124 marker_warning: Color,
125 marker_log: Color,
126 line_number_normal: Color,
127 line_number_highlight: Color,
128 whitespace: Color,
129 keyword: Color,
130 flow: Color,
131 looping: Color,
132 identifier: Color,
133 call: Color,
134 type_name: Color,
135 theme_name: Color,
136 string: Color,
137 number: Color,
138 comment: Color,
139 doc_comment: Color,
140 paren_d1: Color,
141 paren_d2: Color,
142 operator: Color,
143 delimiter: Color,
144 unexpected: Color,
145 warning: Color,
146 error: Color,
147 defocus: Color,
148}
149
150impl TextEditor {
151
152 pub fn proto(cx: &mut Cx) -> Self {
153 Self {
154 read_only: false,
155 multiline: true,
156 cursors: TextCursorSet::new(),
157 indent_lines: Quad {
158 z: 0.001,
159 ..Quad::proto(cx)
160 },
161 view: ScrollView::proto(cx),
162 bg: Quad ::proto(cx),
163 shadow: ScrollShadow {
164 z: 10.,
165 ..ScrollShadow::proto(cx)
166 },
167 gutter_bg: Quad {
168 z: 9.0,
169 ..Quad::proto(cx)
170 },
171 colors: CodeEditorColors::default(),
172 selection: Quad {
173 z: 0.,
174 ..Quad::proto(cx)
175 },
176 token_highlight: Quad::proto(cx),
177 cursor: Quad::proto(cx),
178 cursor_row: Quad::proto(cx),
179 paren_pair: Quad::proto(cx),
180 message_marker: Quad::proto(cx),
181 view_layout: Layout::default(),
183 text: Text {
184 z: 2.00,
185 wrapping: Wrapping::Line,
186 ..Text::proto(cx)
187 },
188 line_number_text: Text {
189 z: 9.,
190 wrapping: Wrapping::Line,
191 ..Text::proto(cx)
192 },
193 open_font_scale: 1.0,
195 folded_font_scale: 0.07,
196 line_number_width: 45.,
197 line_number_click_margin: 10.,
198 draw_line_numbers: true,
199 cursor_blink_speed: 0.5,
200 top_padding: 27.,
201 mark_unmatched_parens: true,
202 highlight_area_on: true,
203 draw_cursor_row: true,
204 _scroll_pos_on_load: None,
205 _jump_to_offset: true,
206 _monospace_size: Vec2::default(),
207 _monospace_base: Vec2::default(),
208 _last_finger_move: None,
209 _tokens_on_line: 0,
210 _line_was_folded: false,
211 _scroll_pos: Vec2::default(),
213 _visible_lines: 0,
214 _undo_id: 0,
215
216
217 _line_geometry: Vec::new(),
218
219 _anim_select: Vec::new(),
220 _grid_select_corner: None,
221 _is_row_select: false,
222 _view_area: Area::Empty,
223 _highlight_area: Area::Empty,
225 _highlight_visibility: 0.,
226 _bg_inst: None,
227 _text_inst: None,
228 _text_area: Area::Empty,
229 _line_number_inst: None,
230 _line_number_chunk: Vec::new(),
231
232 _anim_font_scale: 1.0,
233 _line_largest_font: 0.,
234 _final_fill_height: 0.,
235 folding_depth: 2,
236 _anim_folding: AnimFolding {
237 state: AnimFoldingState::Open,
238 focussed_line: 0,
239 did_animate: false,
240 },
241 _select_scroll: None,
242 _draw_cursors: DrawCursors::new(),
243 _draw_search: DrawCursors::new(),
244 _draw_messages: DrawCursors::new(),
245
246 _paren_stack: Vec::new(),
247 _indent_stack: Vec::new(),
248 _indent_id_alloc: 0.0,
249 _indent_line_inst: None,
250
251 _line_chunk: Vec::new(),
252 _highlight_selection: Vec::new(),
253 _highlight_token: Vec::new(),
254 _last_cursor_pos: TextPos::zero(),
255 _last_indent_color: Color::default(),
256
257 _cursor_blink_timer: Timer::empty(),
258 _cursor_blink_flipflop: 0.,
259 _cursor_area: Area::Empty,
260 _last_lag_mutation_id: 0,
261 _last_tabs: 0,
262 _newline_tabs: 0,
263 _jump_to_offset_id: 0
264 }
265 }
266
267 pub fn gutter_width() -> FloatId {uid!()}
268 pub fn padding_top() -> FloatId {uid!()}
269 pub fn shadow_size() -> FloatId {uid!()}
270
271 pub fn layout_bg() -> LayoutId {uid!()}
272 pub fn text_style_editor_text() -> TextStyleId {uid!()}
273
274 pub fn color_bg() -> ColorId {uid!()}
275 pub fn color_gutter_bg() -> ColorId {uid!()}
276
277 pub fn color_selection() -> ColorId {uid!()}
278 pub fn color_selection_defocus() -> ColorId {uid!()}
279 pub fn color_highlight() -> ColorId {uid!()}
280 pub fn color_cursor() -> ColorId {uid!()}
281 pub fn color_cursor_row() -> ColorId {uid!()}
282
283 pub fn color_indent_line_unknown() -> ColorId {uid!()}
284 pub fn color_indent_line_fn() -> ColorId {uid!()}
285 pub fn color_indent_line_typedef() -> ColorId {uid!()}
286 pub fn color_indent_line_looping() -> ColorId {uid!()}
287 pub fn color_indent_line_flow() -> ColorId {uid!()}
288 pub fn color_paren_pair_match() -> ColorId {uid!()}
289 pub fn color_paren_pair_fail() -> ColorId {uid!()}
290 pub fn color_marker_error() -> ColorId {uid!()}
291 pub fn color_marker_warning() -> ColorId {uid!()}
292 pub fn color_marker_log() -> ColorId {uid!()}
293 pub fn color_line_number_normal() -> ColorId {uid!()}
294 pub fn color_line_number_highlight() -> ColorId {uid!()}
295
296 pub fn color_whitespace() -> ColorId {uid!()}
297 pub fn color_keyword() -> ColorId {uid!()}
298 pub fn color_flow() -> ColorId {uid!()}
299 pub fn color_looping() -> ColorId {uid!()}
300 pub fn color_identifier() -> ColorId {uid!()}
301 pub fn color_call() -> ColorId {uid!()}
302 pub fn color_type_name() -> ColorId {uid!()}
303 pub fn color_theme_name() -> ColorId {uid!()}
304 pub fn color_string() -> ColorId {uid!()}
305 pub fn color_number() -> ColorId {uid!()}
306 pub fn color_comment() -> ColorId {uid!()}
307 pub fn color_doc_comment() -> ColorId {uid!()}
308 pub fn color_paren_d1() -> ColorId {uid!()}
309 pub fn color_paren_d2() -> ColorId {uid!()}
310 pub fn color_operator() -> ColorId {uid!()}
311 pub fn color_delimiter() -> ColorId {uid!()}
312 pub fn color_unexpected() -> ColorId {uid!()}
313 pub fn color_warning() -> ColorId {uid!()}
314 pub fn color_error() -> ColorId {uid!()}
315 pub fn color_defocus() -> ColorId {uid!()}
316
317 pub fn shader_bg() -> ShaderId {uid!()}
318 pub fn shader_indent_lines() -> ShaderId {uid!()}
319 pub fn shader_cursor() -> ShaderId {uid!()}
320 pub fn shader_selection() -> ShaderId {uid!()}
321 pub fn shader_paren_pair() -> ShaderId {uid!()}
322 pub fn shader_cursor_row() -> ShaderId {uid!()}
323 pub fn shader_token_highlight() -> ShaderId {uid!()}
324 pub fn shader_message_marker() -> ShaderId {uid!()}
325
326 pub fn instance_indent_id() -> InstanceFloat {uid!()}
327 pub fn uniform_indent_sel() -> UniformFloat {uid!()}
328 pub fn uniform_cursor_blink() -> UniformFloat {uid!()}
329 pub fn instance_select_prev_x() -> InstanceFloat {uid!()}
330 pub fn instance_select_prev_w() -> InstanceFloat {uid!()}
331 pub fn instance_select_next_x() -> InstanceFloat {uid!()}
332 pub fn instance_select_next_w() -> InstanceFloat {uid!()}
333 pub fn uniform_highlight_visible() -> UniformFloat {uid!()}
334 pub fn instance_shadow_dir() -> InstanceFloat {uid!()}
335
336 pub fn style(cx: &mut Cx, _opt: &StyleOptions) {
337
338 Self::shadow_size().set(cx, 6.0);
339 Self::gutter_width().set(cx, 45.0);
340 Self::padding_top().set(cx, 27.);
341 Self::text_style_editor_text().set(cx, Theme::text_style_fixed().get(cx));
342
343 Self::shader_indent_lines().set(cx, Quad::def_quad_shader().compose(shader_ast !({
344 let indent_id: Self::instance_indent_id();
345 let indent_sel: Self::uniform_indent_sel();
347 fn pixel() -> vec4 {
348 let col = color;
349 let thickness = 0.8 + dpi_dilate * 0.5;
350 if indent_id == indent_sel {
351 col *= vec4(1., 1., 1., 1.);
352 thickness *= 1.3;
353 }
354 else {
355 col *= vec4(0.75, 0.75, 0.75, 0.75);
356 }
357 df_viewport(pos * vec2(w, h));
358 df_move_to(1., -1.);
359 df_line_to(1., h + 1.);
360 return df_stroke(col, thickness);
361 }
362 })));
363
364 Self::shader_cursor().set(cx, Quad::def_quad_shader().compose(shader_ast !({
365 let blink: Self::uniform_cursor_blink();
366 fn pixel() -> vec4 {
367 if blink<0.5 {
368 return vec4(color.rgb * color.a, color.a)
369 }
370 else {
371 return vec4(0., 0., 0., 0.);
372 }
373 }
374 })));
375
376 Self::shader_selection().set(cx, Quad::def_quad_shader().compose(shader_ast !({
377 let prev_x: Self::instance_select_prev_x();
378 let prev_w: Self::instance_select_prev_w();
379 let next_x: Self::instance_select_next_x();
380 let next_w: Self::instance_select_next_w();
381 const gloopiness: float = 8.;
382 const border_radius: float = 2.;
383
384 fn vertex() -> vec4 { let shift: vec2 = -draw_scroll.xy;
386 let clipped: vec2 = clamp(
387 geom * vec2(w + 16., h) + vec2(x, y) + shift - vec2(8., 0.),
388 draw_clip.xy,
389 draw_clip.zw
390 );
391 pos = (clipped - shift - vec2(x, y)) / vec2(w, h);
392 return camera_projection * (camera_view * (view_transform * vec4(clipped.x, clipped.y, z + draw_zbias, 1.)));
393 }
394
395 fn pixel() -> vec4 {
396 df_viewport(pos * vec2(w, h));
397 df_box(0., 0., w, h, border_radius);
398 if prev_w > 0. {
399 df_box(prev_x, -h, prev_w, h, border_radius);
400 df_gloop(gloopiness);
401 }
402 if next_w > 0. {
403 df_box(next_x, h, next_w, h, border_radius);
404 df_gloop(gloopiness);
405 }
406 return df_fill(color);
408 }
409 })));
410
411 Self::shader_paren_pair().set(cx, Quad::def_quad_shader().compose(shader_ast!({
412 fn pixel() -> vec4 {
413 df_viewport(pos * vec2(w, h));
414 df_rect(0., h - 1.5 - dpi_dilate, w, 1.5 + dpi_dilate);
419 return df_fill(color);
420 }
423 })));
424
425 Self::shader_cursor_row().set(cx, Quad::def_quad_shader().compose(shader_ast!({
426 fn pixel() -> vec4 {
427 df_viewport(pos * vec2(w, h));
428 df_rect(0., 0., w, h);
429 return df_fill(color);
430 }
437 })));
438 Self::shader_token_highlight().set(cx, Quad::def_quad_shader().compose(shader_ast!({
448 let visible: Self::uniform_highlight_visible();
449 fn pixel() -> vec4 {
450 if visible<0.5 {
451 return vec4(0., 0., 0., 0.)
452 }
453 df_viewport(pos * vec2(w, h));
454 df_box(0.5, 0.5, w - 1., h - 1., 1.);
455 return df_fill(color);
456 }
457 })));
458
459 Self::shader_message_marker().set(cx, Quad::def_quad_shader().compose(shader_ast!({
460 fn pixel() -> vec4 {
461 let pos2 = vec2(pos.x, pos.y + 0.03 * sin(pos.x * w));
462 df_viewport(pos2 * vec2(w, h));
463 df_move_to(0., h - 1.);
465 df_line_to(w, h - 1.);
466 return df_stroke(color, 0.8);
467 }
468 })));
469
470 Self::shader_bg().set(cx, Quad::def_quad_shader().compose(shader_ast!({
471 fn pixel() -> vec4 {
472 return vec4(color.rgb * color.a, color.a);
473 }
474 })));
475 }
476
477 pub fn apply_style(&mut self, cx: &mut Cx) {
478 self.colors.indent_line_unknown = Self::color_indent_line_unknown().get(cx);
480 self.colors.indent_line_fn = Self::color_indent_line_fn().get(cx);
481 self.colors.indent_line_typedef = Self::color_indent_line_typedef().get(cx);
482 self.colors.indent_line_looping = Self::color_indent_line_looping().get(cx);
483 self.colors.indent_line_flow = Self::color_indent_line_flow().get(cx);
484
485 self.colors.paren_pair_match = Self::color_paren_pair_match().get(cx);
486 self.colors.paren_pair_fail = Self::color_paren_pair_fail().get(cx);
487 self.colors.marker_error = Self::color_marker_error().get(cx);
488 self.colors.marker_warning = Self::color_marker_warning().get(cx);
489 self.colors.marker_log = Self::color_marker_log().get(cx);
490 self.colors.line_number_normal = Self::color_line_number_normal().get(cx);
491 self.colors.line_number_highlight = Self::color_line_number_highlight().get(cx);
492 self.colors.whitespace = Self::color_whitespace().get(cx);
493 self.colors.keyword = Self::color_keyword().get(cx);
494 self.colors.flow = Self::color_flow().get(cx);
495 self.colors.looping = Self::color_looping().get(cx);
496 self.colors.identifier = Self::color_identifier().get(cx);
497 self.colors.call = Self::color_call().get(cx);
498 self.colors.type_name = Self::color_type_name().get(cx);
499 self.colors.theme_name = Self::color_theme_name().get(cx);
500 self.colors.string = Self::color_string().get(cx);
501 self.colors.number = Self::color_number().get(cx);
502 self.colors.comment = Self::color_comment().get(cx);
503 self.colors.doc_comment = Self::color_doc_comment().get(cx);
504 self.colors.paren_d1 = Self::color_paren_d1().get(cx);
505 self.colors.paren_d2 = Self::color_paren_d2().get(cx);
506 self.colors.operator = Self::color_operator().get(cx);
507 self.colors.delimiter = Self::color_delimiter().get(cx);
508 self.colors.unexpected = Self::color_unexpected().get(cx);
509 self.colors.warning = Self::color_warning().get(cx);
510 self.colors.error = Self::color_error().get(cx);
511 self.colors.defocus = Self::color_defocus().get(cx);
512 self.bg.color = Self::color_bg().get(cx);
513 self.gutter_bg.color = Self::color_gutter_bg().get(cx);
514
515 self.line_number_width = Self::gutter_width().get(cx);
516 self.top_padding = Self::padding_top().get(cx);
517
518 self.selection.color = if self.has_key_focus(cx) {
519 Self::color_selection().get(cx)
520 }else {
521 Self::color_selection_defocus().get(cx)
522 };
523 self.token_highlight.color = Self::color_highlight().get(cx);
524 self.cursor.color = Self::color_cursor().get(cx);
525 self.cursor_row.color = Self::color_cursor_row().get(cx);
526 self.text.text_style = Self::text_style_editor_text().get(cx);
527 self.line_number_text.text_style = Self::text_style_editor_text().get(cx);
528
529 self.bg.shader = Self::shader_bg().get(cx);
530 self.indent_lines.shader = Self::shader_indent_lines().get(cx);
531 self.cursor.shader = Self::shader_cursor().get(cx);
532 self.selection.shader = Self::shader_selection().get(cx);
533 self.paren_pair.shader = Self::shader_paren_pair().get(cx);
534 self.cursor_row.shader = Self::shader_cursor_row().get(cx);
535 self.token_highlight.shader = Self::shader_token_highlight().get(cx);
536 self.message_marker.shader = Self::shader_message_marker().get(cx);
537 }
538
539 fn reset_highlight_visible(&mut self, cx: &mut Cx) {
540 self._highlight_visibility = 0.0;
541 self._highlight_area.write_uniform_float(cx, Self::uniform_highlight_visible(), self._highlight_visibility);
542 }
543
544 fn reset_cursor_blinker(&mut self, cx: &mut Cx) {
545 cx.stop_timer(&mut self._cursor_blink_timer);
546 self._cursor_blink_timer = cx.start_timer(self.cursor_blink_speed * 0.5, false);
547 self._cursor_blink_flipflop = 0.;
548 self._cursor_area.write_uniform_float(cx, Self::uniform_cursor_blink(), self._cursor_blink_flipflop);
549 }
550
551 fn handle_finger_down(&mut self, cx: &mut Cx, fe: &FingerDownEvent, text_buffer: &mut TextBuffer) {
552 cx.set_down_mouse_cursor(MouseCursor::Text);
553 self.set_key_focus(cx);
555 self._undo_id += 1;
556
557 let offset;
558 if fe.rel.x < self.line_number_width - self.line_number_click_margin {
560 offset = self.compute_offset_from_ypos(cx, fe.abs.y, text_buffer, false);
561 let range = text_buffer.get_nearest_line_range(offset);
562 self.cursors.set_last_clamp_range(range);
563 self._is_row_select = true;
564 }
565 else {
566 offset = self.text.find_closest_offset(cx, &self._text_area, fe.abs);
567 match fe.tap_count {
568 1 => {
569 },
570 2 => {
571 if let Some((coffset, len)) = TextCursorSet::get_nearest_token_chunk(offset, &text_buffer) {
572 self.cursors.set_last_clamp_range((coffset, len));
573 }
574 },
575 3 => {
576 if let Some((coffset, len)) = TextCursorSet::get_nearest_token_chunk(offset, &text_buffer) {
577 let (start, line_len) = text_buffer.get_nearest_line_range(offset);
579 let mut chunk_offset = coffset;
580 let mut chunk_len = len;
581 if start < chunk_offset {
582 chunk_len += chunk_offset - start;
583 chunk_offset = start;
584 if line_len > chunk_len {
585 chunk_len = line_len;
586 }
587 }
588 self.cursors.set_last_clamp_range((chunk_offset, chunk_len));
589 }
590 else {
591 let range = text_buffer.get_nearest_line_range(offset);
592 self.cursors.set_last_clamp_range(range);
593 }
594 },
595 _ => {
596 }
599 }
600 }
602
603 if fe.modifiers.shift {
604 if fe.modifiers.logo || fe.modifiers.control { let pos = self.compute_grid_text_pos_from_abs(cx, fe.abs);
606 self._grid_select_corner = Some(self.cursors.grid_select_corner(pos, text_buffer));
607 self.cursors.grid_select(self._grid_select_corner.unwrap(), pos, text_buffer);
608 if self.cursors.set.len() == 0 {
609 self.cursors.clear_and_set_last_cursor_head_and_tail(offset, text_buffer);
610 }
611 }
612 else { self.cursors.clear_and_set_last_cursor_head(offset, text_buffer);
614 }
615 }
616 else { if fe.modifiers.logo || fe.modifiers.control {
618 self.cursors.add_last_cursor_head_and_tail(offset, text_buffer);
619 }
620 else {
621 self.cursors.clear_and_set_last_cursor_head_and_tail(offset, text_buffer);
622 }
623 }
624
625 self.view.redraw_view_area(cx);
626 self._last_finger_move = Some(fe.abs);
627 self.update_highlight(cx, text_buffer);
628 self.reset_cursor_blinker(cx);
629 }
630
631 fn handle_finger_move(&mut self, cx: &mut Cx, fe: &FingerMoveEvent, text_buffer: &mut TextBuffer) {
632 let cursor_moved = if let Some(grid_select_corner) = self._grid_select_corner {
633 let pos = self.compute_grid_text_pos_from_abs(cx, fe.abs);
634 self.cursors.grid_select(grid_select_corner, pos, text_buffer)
635 }
636 else if self._is_row_select {
637 let offset = self.compute_offset_from_ypos(cx, fe.abs.y, text_buffer, true);
638 self.cursors.set_last_cursor_head(offset, text_buffer)
639 }
640 else {
641 let offset = self.text.find_closest_offset(cx, &self._text_area, fe.abs);
642 self.cursors.set_last_cursor_head(offset, text_buffer)
643 };
644 self._last_finger_move = Some(fe.abs);
645 let repaint_scroll = self.check_select_scroll_dynamics(&fe);
647 if cursor_moved {
648 self.update_highlight(cx, text_buffer);
649 };
650 if repaint_scroll || cursor_moved {
651 self.view.redraw_view_area(cx);
652 }
653 if cursor_moved {
654 self.reset_cursor_blinker(cx);
655 }
656 }
657
658 fn handle_finger_up(&mut self, cx: &mut Cx, _fe: &FingerUpEvent, text_buffer: &mut TextBuffer) {
659 self.cursors.clear_last_clamp_range();
660 self._select_scroll = None;
661 self._last_finger_move = None;
662 self._grid_select_corner = None;
663 self._is_row_select = false;
664 self.update_highlight(cx, text_buffer);
665 self.reset_cursor_blinker(cx);
666 }
667
668 fn handle_key_down(&mut self, cx: &mut Cx, ke: &KeyEvent, text_buffer: &mut TextBuffer) {
669 let cursor_moved = match ke.key_code {
670 KeyCode::ArrowUp => {
671 if ke.modifiers.logo || ke.modifiers.control {
672 false
673 }
674 else {
675 if self._anim_folding.state.is_folded() && self.cursors.set.len() == 1 {
676 let delta = self.compute_next_unfolded_line_up(text_buffer);
678 self.cursors.move_up(delta, ke.modifiers.shift, text_buffer);
679 }
680 else {
681 self.cursors.move_up(1, ke.modifiers.shift, text_buffer);
682 }
683 self._undo_id += 1;
684 true
685 }
686 },
687 KeyCode::ArrowDown => {
688 if ke.modifiers.logo || ke.modifiers.control {
689 false
690 }
691 else {
692 if self._anim_folding.state.is_folded() && self.cursors.set.len() == 1 {
693 let delta = self.compute_next_unfolded_line_down(text_buffer);
695 self.cursors.move_down(delta, ke.modifiers.shift, text_buffer);
696 }
697 else {
698 self.cursors.move_down(1, ke.modifiers.shift, text_buffer);
699 }
700 self._undo_id += 1;
701 true
702 }
703 },
704 KeyCode::ArrowLeft => {
705 if ke.modifiers.logo || ke.modifiers.control { self.cursors.move_left_nearest_token(ke.modifiers.shift, text_buffer)
707 }
708 else {
709 self.cursors.move_left(1, ke.modifiers.shift, text_buffer);
710 }
711 self._undo_id += 1;
712 true
713 },
714 KeyCode::ArrowRight => {
715 if ke.modifiers.logo || ke.modifiers.control { self.cursors.move_right_nearest_token(ke.modifiers.shift, text_buffer)
717 }
718 else {
719 self.cursors.move_right(1, ke.modifiers.shift, text_buffer);
720 }
721 self._undo_id += 1;
722 true
723 },
724 KeyCode::PageUp => {
725 self.cursors.move_up(self._visible_lines.max(5) - 4, ke.modifiers.shift, text_buffer);
726 self._undo_id += 1;
727 true
728 },
729 KeyCode::PageDown => {
730 self.cursors.move_down(self._visible_lines.max(5) - 4, ke.modifiers.shift, text_buffer);
731 self._undo_id += 1;
732 true
733 },
734 KeyCode::Home => {
735 self.cursors.move_home(ke.modifiers.shift, text_buffer);
736 self._undo_id += 1;
737 true
738 },
739 KeyCode::End => {
740 self.cursors.move_end(ke.modifiers.shift, text_buffer);
741 self._undo_id += 1;
742 true
743 },
744 KeyCode::Backspace => {
745 if !self.read_only {
746 self.cursors.backspace(text_buffer, self._undo_id);
747 true
748 }
749 else {
750 false
751 }
752 },
753 KeyCode::Delete => {
754 if !self.read_only {
755 self.cursors.delete(text_buffer);
756 true
757 }
758 else {
759 false
760 }
761 },
762 KeyCode::KeyZ => {
763 if !self.read_only {
764 if ke.modifiers.logo || ke.modifiers.control {
765 if ke.modifiers.shift { text_buffer.redo(true, &mut self.cursors);
767 true
768 }
769 else { text_buffer.undo(true, &mut self.cursors);
771 true
772 }
773 }
774 else {
775 false
776 }
777 }
778 else {
779 false
780 }
781 },
782 KeyCode::KeyX => { if !self.read_only && (ke.modifiers.logo || ke.modifiers.control) { self.cursors.replace_text("", text_buffer);
785 true
786 }
787 else {
788 false
789 }
790 },
791 KeyCode::KeyA => { if ke.modifiers.logo || ke.modifiers.control { self.cursors.select_all(text_buffer);
794 self.view.redraw_view_area(cx);
796 false
797 }
798 else {
799 false
800 }
801 },
802 KeyCode::Alt => {
803 self.start_code_folding(cx, text_buffer);
806 false
807 },
809 KeyCode::Tab => {
810 if !self.read_only {
811 if ke.modifiers.shift {
812 self.cursors.remove_tab(text_buffer, 4);
813 }
814 else {
815 self.cursors.insert_tab(text_buffer, " ");
816 }
817 true
818 }
819 else {
820 false
821 }
822 },
823 KeyCode::Return => {
824 if !self.read_only && self.multiline {
825 if !ke.modifiers.control && !ke.modifiers.logo {
826 self.cursors.insert_newline_with_indent(text_buffer);
827 }
828 true
829 }
830 else {
831 false
832 }
833 },
834 _ => false
835 };
836 if cursor_moved {
837 self.update_highlight(cx, text_buffer);
838 self.scroll_last_cursor_visible(cx, text_buffer, 0.);
839 self.view.redraw_view_area(cx);
840 self.reset_cursor_blinker(cx);
841 }
842 }
843
844 fn handle_text_input(&mut self, cx: &mut Cx, te: &TextInputEvent, text_buffer: &mut TextBuffer) {
845 if te.replace_last {
846 text_buffer.undo(false, &mut self.cursors);
847 }
848
849 if !te.was_paste && te.input.len() == 1 {
850 match te.input.chars().next().unwrap() {
851 '(' => {
852 self.cursors.insert_around("(", ")", text_buffer);
853 },
854 '[' => {
855 self.cursors.insert_around("[", "]", text_buffer);
856 },
857 '{' => {
858 self.cursors.insert_around("{", "}", text_buffer);
859 },
860 '"' => {
861 self.cursors.insert_around("\"", "\"", text_buffer);
862 },
863 ')' => {
864 self.cursors.overwrite_if_exists_or_deindent(")", 4, text_buffer);
865 },
866 ']' => {
867 self.cursors.overwrite_if_exists_or_deindent("]", 4, text_buffer);
868 },
869 '}' => {
870 self.cursors.overwrite_if_exists_or_deindent("}", 4, text_buffer);
871 },
872 _ => {
873 self.cursors.replace_text(&te.input, text_buffer);
874 }
875 }
876 }
878 else {
879 if !self.multiline {
880 let replaced = te.input.replace("\n", "");
881 self.cursors.replace_text(&replaced, text_buffer);
882 }
883 else {
884 self.cursors.replace_text(&te.input, text_buffer);
885 }
886 }
887 self.update_highlight(cx, text_buffer);
888 self.scroll_last_cursor_visible(cx, text_buffer, 0.);
889 self.view.redraw_view_area(cx);
890 self.reset_cursor_blinker(cx);
891
892 cx.send_signal(text_buffer.signal, TextBuffer::status_data_update());
893
894 }
895
896 pub fn handle_text_editor(&mut self, cx: &mut Cx, event: &mut Event, text_buffer: &mut TextBuffer) -> TextEditorEvent {
897 if self.view.handle_scroll_bars(cx, event) {
898 if let Some(last_finger_move) = self._last_finger_move {
899 if let Some(grid_select_corner) = self._grid_select_corner {
900 let pos = self.compute_grid_text_pos_from_abs(cx, last_finger_move);
901 self.cursors.grid_select(grid_select_corner, pos, text_buffer);
902 }
903 else {
904 let offset = self.text.find_closest_offset(cx, &self._text_area, last_finger_move);
905 self.cursors.set_last_cursor_head(offset, text_buffer);
906 }
907 }
908 self.view.redraw_view_area(cx);
912 }
913 let last_mutation_id = text_buffer.mutation_id;
914 match event {
916 Event::Timer(te) => if self._cursor_blink_timer.is_timer(te) {
917 if self.has_key_focus(cx) {
918 self._cursor_blink_timer = cx.start_timer(self.cursor_blink_speed, false);
919 }
920 self._cursor_blink_flipflop = 1.0 - self._cursor_blink_flipflop;
922 self._undo_id += 1;
923 self._highlight_visibility = 1.0;
924 self._cursor_area.write_uniform_float(cx, Self::uniform_cursor_blink(), self._cursor_blink_flipflop);
925 if self.highlight_area_on {
926 self._highlight_area.write_uniform_float(cx, Self::uniform_highlight_visible(), self._highlight_visibility);
927 }
928 if self._last_lag_mutation_id != text_buffer.mutation_id {
930 let was_filechange = self._last_lag_mutation_id != 0;
931 self._last_lag_mutation_id = text_buffer.mutation_id;
932 if was_filechange {
933 return TextEditorEvent::LagChange;
934 }
935 }
936 },
937 Event::Signal(se) => if text_buffer.signal == se.signal {
938 if se.status == TextBuffer::status_loaded()
939 || se.status == TextBuffer::status_message_update()
940 || se.status == TextBuffer::status_data_update(){
941 self.view.redraw_view_area(cx);
942 }
943 else if se.status == TextBuffer::status_jump_to_offset(){
944 if !text_buffer.is_loaded {
945 self._jump_to_offset = true;
946 }
947 else {
948 self.do_jump_to_offset(cx, text_buffer);
949 }
950 }
951 else if se.status == TextBuffer::status_keyboard_update(){
952 if let Some(key_down) = &text_buffer.keyboard.key_down {
953 match key_down {
954 KeyCode::Alt => {
955 self.start_code_folding(cx, text_buffer);
956 },
957 _ => ()
958 }
959 }
960 if let Some(key_up) = &text_buffer.keyboard.key_up {
961 match key_up {
962 KeyCode::Alt => {
963 self.start_code_unfolding(cx, text_buffer);
964 },
965 _ => ()
966 }
967 }
968 }
969 },
970 _ => ()
971 }
972 match event.hits(cx, self.view.get_view_area(cx), HitOpt::default()) {
974 Event::KeyFocusLost(_kf) => {
975 self.view.redraw_view_area(cx)
976 },
977 Event::FingerDown(fe) => {
978 self.handle_finger_down(cx, &fe, text_buffer);
979 },
980 Event::FingerHover(_fe) => {
981 cx.set_hover_mouse_cursor(MouseCursor::Text);
982 },
983 Event::FingerUp(fe) => {
984 self.handle_finger_up(cx, &fe, text_buffer);
985 },
986 Event::FingerMove(fe) => {
987 self.handle_finger_move(cx, &fe, text_buffer);
988 },
989 Event::KeyDown(ke) => {
990 if ke.key_code == KeyCode::Return && (ke.modifiers.logo || ke.modifiers.control) {
991 return TextEditorEvent::AutoFormat
992 }
993 self.handle_key_down(cx, &ke, text_buffer);
994 },
995 Event::KeyUp(ke) => {
996 match ke.key_code {
997 KeyCode::Alt => {
998 self.start_code_unfolding(cx, text_buffer);
999 },
1000 _ => (),
1001 }
1002 self.reset_cursor_blinker(cx);
1003 },
1004 Event::TextInput(te) => {
1005 if !self.read_only {
1006 self.handle_text_input(cx, &te, text_buffer);
1007 }
1008 },
1009 Event::TextCopy(_) => match event { Event::TextCopy(req) => {
1011 req.response = Some(self.cursors.get_all_as_string(text_buffer));
1012 },
1013 _ => ()
1014 },
1015 _ => ()
1016 };
1017 if last_mutation_id != text_buffer.mutation_id{
1018 TextEditorEvent::Change
1019 }
1020 else{
1021 TextEditorEvent::None
1022 }
1023 }
1024
1025 pub fn has_key_focus(&self, cx: &Cx) -> bool {
1026 cx.has_key_focus(self._view_area)
1027 }
1028
1029 pub fn set_key_focus(&mut self, cx: &mut Cx) {
1030 cx.set_key_focus(self._view_area);
1031 self.reset_cursor_blinker(cx);
1032 }
1033
1034
1035 pub fn begin_text_editor(&mut self, cx: &mut Cx, text_buffer: &TextBuffer) -> Result<(), ()> {
1036 self.view.begin_view(cx, self.view_layout) ?;
1038
1039 self.apply_style(cx);
1040
1041 self._last_indent_color = self.colors.indent_line_unknown;
1042 if !text_buffer.is_loaded {
1045 self.text.color = color("#666");
1050 self.text.draw_text(cx, "...");
1051 self.view.end_view(cx);
1054 return Err(())
1055 }
1056 else {
1057 let inst = self.bg.begin_quad_fill(cx);
1058 inst.set_do_scroll(cx, false, false); self._bg_inst = Some(inst);
1060
1061 let view_area = self.view.get_view_area(cx);
1063 cx.update_area_refs(self._view_area, view_area);
1064 self._view_area = view_area;
1066 self._highlight_area = cx.new_instance_draw_call(&self.token_highlight.shader, 0).into();
1068 cx.new_instance_draw_call(&self.cursor_row.shader, 0);
1070 cx.new_instance_draw_call(&self.selection.shader, 0);
1071 cx.new_instance_draw_call(&self.message_marker.shader, 0);
1072 cx.new_instance_draw_call(&self.paren_pair.shader, 0);
1073
1074 self._text_inst = Some(self.text.begin_text(cx));
1076 self._indent_line_inst = Some(cx.new_instance_draw_call(&self.indent_lines.shader, 0));
1077
1078 self._cursor_area = cx.new_instance_draw_call(&self.cursor.shader, 0).into();
1079
1080 if self.draw_line_numbers {
1081 let inst = self.gutter_bg.draw_quad_rel(cx, Rect {x: 0., y: 0., w: self.line_number_width, h: cx.get_height_total()});
1082 inst.set_do_scroll(cx, false, false);
1083 cx.new_instance_draw_call(&self.text.shader, 0);
1084 let inst = self.line_number_text.begin_text(cx);
1085 inst.inst.set_do_scroll(cx, false, true);
1086 self._line_number_inst = Some(inst);
1087 }
1088
1089 if let Some(select_scroll) = &mut self._select_scroll {
1090 let scroll_pos = self.view.get_scroll_pos(cx);
1091 if self.view.set_scroll_pos(cx, Vec2 {
1092 x: scroll_pos.x + select_scroll.delta.x,
1093 y: scroll_pos.y + select_scroll.delta.y
1094 }) {
1095 self.view.redraw_view_area(cx);
1096 }
1097 else {
1098 select_scroll.at_end = true;
1099 }
1100 }
1101
1102 self._monospace_base = self.text.get_monospace_base(cx);
1104 self.set_font_scale(cx, self.open_font_scale);
1105 self._draw_cursors = DrawCursors::new();
1106 self._draw_messages = DrawCursors::new();
1107 self._tokens_on_line = 0;
1108 self._visible_lines = 0;
1109 self._newline_tabs = 0;
1110 self._last_tabs = 0;
1111 self._indent_stack.truncate(0);
1112 self._indent_id_alloc = 1.0;
1113 self._paren_stack.truncate(0);
1114 self._draw_cursors.set_next(&self.cursors.set);
1115 if text_buffer.messages.mutation_id != text_buffer.mutation_id {
1116 self._draw_messages.term(&text_buffer.messages.cursors);
1117 }
1118 else {
1119 self._draw_messages.set_next(&text_buffer.messages.cursors);
1120 }
1121 self._last_cursor_pos = self.cursors.get_last_cursor_text_pos(text_buffer);
1122
1123 cx.move_turtle(self.line_number_width, self.top_padding);
1125
1126 self.do_folding_animation_step(cx);
1128
1129 self._line_geometry.truncate(0);
1130 self._line_largest_font = self.text.text_style.font_size;
1131 self._scroll_pos = self.view.get_scroll_pos(cx);
1132
1133 return Ok(())
1134 }
1135 }
1136
1137 fn do_folding_animation_step(&mut self, cx: &mut Cx) {
1138 let anim_folding = &mut self._anim_folding;
1140 if anim_folding.state.is_animating() {
1141 anim_folding.state.next_anim_step();
1142 if anim_folding.state.is_animating() {
1143 self.view.redraw_view_area(cx);
1144 }
1145 anim_folding.did_animate = true;
1146 }
1147 else {
1148 anim_folding.did_animate = false;
1149 }
1150 self._anim_font_scale = anim_folding.state.get_font_size(self.open_font_scale, self.folded_font_scale);
1152
1153 if self._anim_folding.did_animate {
1154 let mut ypos = self.top_padding;
1155 let mut ypos_at_line = ypos;
1156 let focus_line = self._anim_folding.focussed_line;
1157 if focus_line < self._line_geometry.len() {
1158 for (line, geom) in self._line_geometry.iter().enumerate() {
1159 if focus_line == line {
1160 ypos_at_line = ypos;
1161 }
1162 ypos += if geom.was_folded {
1163 self._monospace_base.y * self.text.text_style.font_size * self._anim_font_scale
1164 }
1165 else {
1166 self._monospace_base.y * self.text.text_style.font_size
1167 }
1168 }
1169 ypos += self._final_fill_height;
1170 let dy = self._line_geometry[focus_line].walk.y - ypos_at_line;
1171 let sv = self.view.get_scroll_view_total();
1172 self.view.set_scroll_view_total(cx, Vec2 {x: sv.x, y: ypos});
1173 let scroll_pos = self.view.get_scroll_pos(cx);
1174 self.view.set_scroll_pos(cx, Vec2 {
1175 x: scroll_pos.x,
1176 y: scroll_pos.y - dy
1177 });
1178 }
1179 }
1180 }
1181
1182 fn update_highlight(&mut self, cx: &mut Cx, text_buffer: &TextBuffer) {
1183 self._highlight_selection = self.cursors.get_selection_highlight(text_buffer);
1184 let new_token = self.cursors.get_token_highlight(text_buffer);
1185 if new_token != self._highlight_token {
1186 self.reset_highlight_visible(cx);
1187 }
1188 self._highlight_token = new_token;
1189
1190 }
1191
1192 fn draw_new_line(&mut self, cx: &mut Cx) {
1193 let line_geom = LineGeom {
1195 walk: cx.get_rel_turtle_pos(),
1196 font_size: self._line_largest_font,
1197 was_folded: self._line_was_folded,
1198 indent_id: if let Some((_, id)) = self._indent_stack.last() {*id}else {0.}
1199 };
1200
1201 let origin = cx.get_turtle_origin();
1203 if self.draw_line_numbers && cx.turtle_line_is_visible(self._monospace_size.y, self._scroll_pos) {
1204 let chunk = &mut self._line_number_chunk;
1207 chunk.truncate(0);
1208 let line_num = self._line_geometry.len() + 1;
1209 let mut scale = 10000;
1210 let mut fill = false;
1211 loop {
1212 let digit = ((line_num / scale) % 10) as u8;
1213 if digit != 0 {
1214 fill = true;
1215 }
1216 if fill {
1217 chunk.push((48 + digit) as char);
1218 }
1219 else {
1220 chunk.push(' ');
1221 }
1222 if scale <= 1 {
1223 break
1224 }
1225 scale /= 10;
1226 }
1227 if line_num == self._last_cursor_pos.row + 1 {
1228 self.line_number_text.color = self.colors.line_number_highlight;
1229 }
1230 else {
1231 self.line_number_text.color = self.colors.line_number_normal;
1232 }
1233 let chunk_width = self._monospace_size.x * 5.0;
1234 self.line_number_text.add_text(cx, origin.x + (self.line_number_width - chunk_width - self.line_number_click_margin), origin.y + line_geom.walk.y, 0, self._line_number_inst.as_mut().unwrap(), chunk, | _, _, _, _ | {0.});
1235 }
1236
1237 cx.turtle_new_line_min_height(self._monospace_size.y);
1238
1239 cx.move_turtle(self.line_number_width, 0.);
1240
1241 self._tokens_on_line = 0;
1242 self._draw_cursors.process_newline();
1245 self._draw_messages.process_newline();
1246
1247 let hl_len = self._highlight_selection.len();
1249 if hl_len != 0 {
1250 for bp in 0..self._line_chunk.len().max(hl_len) - hl_len {
1251 let mut found = true;
1252 for ip in 0..hl_len {
1253 if self._highlight_selection[ip] != self._line_chunk[bp + ip].1 {
1254 found = false;
1255 break;
1256 }
1257 }
1258 if found { let origin = cx.get_turtle_origin();
1260 let min_x = self._line_chunk[bp].0;
1261 let max_x = self._line_chunk[bp + hl_len].0;
1262 self.draw_token_highlight_quad(cx, Rect {
1263 x: min_x,
1264 y: line_geom.walk.y + origin.y,
1265 w: max_x - min_x,
1266 h: self._monospace_size.y,
1267 });
1268 }
1269 }
1270 self._line_chunk.truncate(0);
1271 }
1272
1273 self._line_geometry.push(line_geom);
1275 self._line_largest_font = self.text.text_style.font_size;
1276 }
1277
1278 fn draw_indent_lines(&mut self, cx: &mut Cx, geom_y: f32, tabs: usize) {
1279 let y_pos = geom_y - cx.get_turtle_origin().y;
1280 let tab_variable_width = self._monospace_base.x * 4. * self.text.text_style.font_size * self._anim_font_scale;
1281 let tab_fixed_width = self._monospace_base.x * 4. * self.text.text_style.font_size;
1282 let mut off = self.line_number_width;
1283 for i in 0..tabs {
1284 let (indent_color, indent_id) = if i < self._indent_stack.len() {self._indent_stack[i]}else {
1285 (self.colors.indent_line_unknown, 0.)
1286 };
1287 let tab_width = if i < self.folding_depth {tab_fixed_width}else {tab_variable_width};
1288 self.indent_lines.color = indent_color;
1289 let inst = self.indent_lines.draw_quad_rel(cx, Rect {
1290 x: off,
1291 y: y_pos,
1292 w: tab_width,
1293 h: self._monospace_size.y
1294 });
1295 off += tab_width;
1296 inst.push_float(cx, indent_id);
1297 }
1298 }
1299
1300 pub fn draw_chunk(&mut self, cx: &mut Cx, token_chunks_index: usize, flat_text: &Vec<char>, token_chunk: &TokenChunk, message_cursors: &Vec<TextCursor>) {
1301 if token_chunk.len == 0 {
1302 return
1303 }
1304
1305 let token_type = token_chunk.token_type;
1306 let chunk = &flat_text[token_chunk.offset..(token_chunk.offset + token_chunk.len)]; let offset = token_chunk.offset; let next_char = token_chunk.next;
1309
1310 if token_type == TokenType::ParenOpen {
1312 self.draw_paren_open(token_chunks_index, offset, next_char, chunk);
1313 }
1314
1315 if self._tokens_on_line == 0 {
1317 let font_scale = match token_type {
1318 TokenType::Whitespace => {
1319 let tabs = chunk.len()>>2;
1320 while tabs > self._indent_stack.len() {
1321 self._indent_stack.push((self._last_indent_color, self._indent_id_alloc));
1322 self._indent_id_alloc += 1.0;
1324 }
1325 while tabs < self._indent_stack.len() {
1326 self._indent_stack.pop();
1327 if let Some(indent) = self._indent_stack.last() {
1328 self._last_indent_color = indent.0;
1329 }
1330 }
1331 if tabs >= self.folding_depth || next_char == '\n' {
1334 let dx = (self._monospace_base.x * self.text.text_style.font_size * 4. * (self.folding_depth as f32)) - (self._monospace_base.x * self.text.text_style.font_size * self._anim_font_scale * 4. * (self.folding_depth as f32));
1336 cx.move_turtle(dx, 0.0);
1337 self._line_was_folded = true;
1338 self._anim_font_scale
1339 }
1340 else {
1341 self._line_was_folded = false;
1342 self.open_font_scale
1343 }
1344 }
1345 TokenType::Newline | TokenType::CommentLine | TokenType::CommentChunk | TokenType::CommentMultiBegin | TokenType::CommentMultiEnd | TokenType::Hash => {
1346 self._line_was_folded = true;
1347 self._anim_font_scale
1348 }
1349 _ => {
1350 self._indent_stack.truncate(0);
1351 self._line_was_folded = false;
1352 self.open_font_scale
1353 }
1354 };
1355 self.set_font_scale(cx, font_scale);
1356 }
1357 if self._tokens_on_line < 4 {
1359 match token_type {
1360 TokenType::Flow => {
1361 self._last_indent_color = self.colors.indent_line_flow;
1362 },
1363 TokenType::Looping => {
1364 self._last_indent_color = self.colors.indent_line_looping;
1365 },
1366 TokenType::TypeDef => {
1367 self._last_indent_color = self.colors.indent_line_typedef;
1368 },
1369 TokenType::Fn | TokenType::Call => {
1370 self._last_indent_color = self.colors.indent_line_fn;
1371 }
1372 _ => ()
1373 }
1374 }
1375 if let Some(geom) = cx.walk_turtle_right_no_wrap(
1377 self._monospace_size.x * (chunk.len() as f32),
1378 self._monospace_size.y,
1379 self._scroll_pos
1380 ) {
1381 let mut mark_spaces = 0.0;
1382 self.text.color = match token_type {
1384 TokenType::Whitespace => {
1385 if self._tokens_on_line == 0 && chunk[0] == ' ' {
1386 let tabs = chunk.len()>>2;
1387 self._last_tabs = tabs;
1389 self._newline_tabs = tabs;
1390 self.draw_indent_lines(cx, geom.y, tabs);
1391 }
1392 else if next_char == '\n' {
1393 mark_spaces = 1.0;
1394 }
1395 self.colors.whitespace
1396 },
1397 TokenType::Newline => {
1398 if self._tokens_on_line == 0 {
1399 self._newline_tabs = 0;
1400 self.draw_indent_lines(cx, geom.y, self._last_tabs);
1401 }
1402 else {
1403 self._last_tabs = self._newline_tabs;
1404 self._newline_tabs = 0;
1405 }
1406 self.colors.whitespace
1407 },
1408 TokenType::BuiltinType => self.colors.keyword,
1409 TokenType::Keyword => self.colors.keyword,
1410 TokenType::Bool => self.colors.keyword,
1411 TokenType::Error => self.colors.error,
1412 TokenType::Warning => self.colors.warning,
1413 TokenType::Defocus => self.colors.defocus,
1414 TokenType::Flow => {
1415 self.colors.flow
1416 }
1417 TokenType::Looping => {
1418 self.colors.looping
1419 }
1420 TokenType::TypeDef => {
1421 self.colors.keyword
1422 }
1423 TokenType::Fn => {
1424 self.colors.keyword
1425 }
1426 TokenType::Identifier => {
1427 if chunk == &self._highlight_token[0..] {
1428 self.draw_token_highlight_quad(cx, geom);
1429
1430 }
1431 self.colors.identifier
1432 }
1433 TokenType::Call => {
1434 if chunk == &self._highlight_token[0..] {
1435 self.draw_token_highlight_quad(cx, geom);
1436 }
1437 self.colors.call
1438 },
1439 TokenType::TypeName => {
1440 if chunk == &self._highlight_token[0..] {
1441 self.draw_token_highlight_quad(cx, geom);
1442 }
1443 self.colors.type_name
1444 },
1445 TokenType::ThemeName => {
1446 if chunk == &self._highlight_token[0..] {
1447 self.draw_token_highlight_quad(cx, geom);
1448 }
1449 self.colors.theme_name
1450 },
1451 TokenType::Regex => self.colors.string,
1452 TokenType::String => self.colors.string,
1453 TokenType::Number => self.colors.number,
1454
1455 TokenType::StringMultiBegin => self.colors.string,
1456 TokenType::StringChunk => self.colors.string,
1457 TokenType::StringMultiEnd => self.colors.string,
1458
1459 TokenType::CommentMultiBegin => self.colors.comment,
1460 TokenType::CommentMultiEnd => self.colors.comment,
1461 TokenType::CommentLine => self.colors.comment,
1462 TokenType::CommentChunk => self.colors.comment,
1463 TokenType::ParenOpen => {
1464 let depth = self._paren_stack.len();
1465 self._paren_stack.last_mut().unwrap().geom_open = Some(geom);
1466 match depth % 2 {
1467 0 => self.colors.paren_d1,
1468 _ => self.colors.paren_d2,
1469 }
1470 },
1471 TokenType::ParenClose => {
1472 if let Some(paren) = self._paren_stack.last_mut() {
1473 paren.geom_close = Some(geom);
1474 }
1475 else {
1476 self.paren_pair.color = self.colors.paren_pair_fail;
1477 self.paren_pair.draw_quad_abs(cx, geom);
1478 }
1479 let depth = self._paren_stack.len();
1480 match depth % 2 {
1481 0 => self.colors.paren_d1,
1482 _ => self.colors.paren_d2,
1483 }
1485 },
1486 TokenType::Operator => self.colors.operator,
1487 TokenType::Namespace => self.colors.operator,
1488 TokenType::Hash => self.colors.operator,
1489 TokenType::Delimiter => self.colors.delimiter,
1490 TokenType::Colon => self.colors.delimiter,
1491 TokenType::Splat => self.colors.operator,
1492 TokenType::Eof => self.colors.unexpected,
1493 TokenType::Unexpected => self.colors.unexpected
1494 };
1495
1496 if self._tokens_on_line == 0 {
1497 self._visible_lines += 1;
1498 }
1500
1501 let cursors = &self.cursors.set;
1502 let last_cursor = self.cursors.last_cursor;
1504 let draw_cursors = &mut self._draw_cursors;
1505 let draw_messages = &mut self._draw_messages;
1506 let height = self._monospace_size.y;
1507
1508 let z = 2.0; if self._highlight_selection.len() > 0 { let line_chunk = &mut self._line_chunk;
1514 self.text.add_text(cx, geom.x, geom.y, offset, self._text_inst.as_mut().unwrap(), &chunk, | ch, offset, x, w | {
1515 line_chunk.push((x, ch));
1516 draw_messages.mark_text_select_only(message_cursors, offset, x, geom.y, w, height);
1518 draw_cursors.mark_text_with_cursor(cursors, ch, offset, x, geom.y, w, height, z, last_cursor, mark_spaces)
1519 });
1520 }
1521 else { self.text.add_text(cx, geom.x, geom.y, offset, self._text_inst.as_mut().unwrap(), &chunk, | ch, offset, x, w | {
1523 draw_messages.mark_text_select_only(message_cursors, offset, x, geom.y, w, height);
1524 draw_cursors.mark_text_with_cursor(cursors, ch, offset, x, geom.y, w, height, z, last_cursor, mark_spaces)
1525 });
1526 }
1527 }
1528 self._tokens_on_line += 1;
1529
1530 if token_chunk.token_type == TokenType::ParenClose {
1532 self.draw_paren_close(cx, token_chunks_index, offset, next_char, chunk);
1533 }
1534 else {
1535 if token_type == TokenType::Newline {
1536 self.draw_new_line(cx);
1537 }
1538 }
1539 }
1540
1541 fn draw_token_highlight_quad(&mut self, cx: &mut Cx, geom: Rect) {
1542 let inst = self.token_highlight.draw_quad_abs(cx, geom);
1543 if inst.need_uniforms_now(cx) {
1544 inst.push_uniform_float(cx, self._highlight_visibility);
1545 }
1546 }
1547
1548 fn draw_paren_open(&mut self, token_chunks_index: usize, offset: usize, next_char: char, chunk: &[char]) {
1549 let marked = if let Some(pos) = self.cursors.get_last_cursor_singular() {
1550 pos == offset || pos == offset + 1 && next_char != '(' && next_char != '{' && next_char != '['
1551 }
1552 else {false};
1553
1554 self._paren_stack.push(ParenItem {
1555 pair_start: token_chunks_index, geom_open: None,
1557 geom_close: None,
1558 marked: marked,
1559 exp_paren: chunk[0]
1560 });
1561 }
1562
1563 fn draw_paren_close(&mut self, cx: &mut Cx, token_chunks_index: usize, offset: usize, next_char: char, chunk: &[char]) {
1564 if self._paren_stack.len() == 0 {
1566 return
1567 }
1568 let last = self._paren_stack.pop().unwrap();
1569 if last.geom_open.is_none() && last.geom_close.is_none() {
1571 return
1572 }
1573 if !self.has_key_focus(cx) {
1574 return
1575 }
1576 if let Some(pos) = self.cursors.get_last_cursor_singular() {
1577 if self.mark_unmatched_parens {
1578 let fail = if last.exp_paren == '(' && chunk[0] != ')' ||
1580 last.exp_paren == '[' && chunk[0] != ']' ||
1581 last.exp_paren == '{' && chunk[0] != '}' {
1582 self.paren_pair.color = self.colors.paren_pair_fail;
1583 true
1584 }
1585 else {
1586 self.paren_pair.color = self.colors.paren_pair_match;
1587 false
1588 };
1589 if fail || pos == offset || pos == offset + 1 && next_char != ')' && next_char != '}' && next_char != ']' || last.marked {
1590 if last.pair_start + 1 == token_chunks_index && !last.geom_open.is_none() && !last.geom_close.is_none() {
1592 let geom_open = last.geom_open.unwrap();
1593 let geom_close = last.geom_open.unwrap();
1594 let geom = Rect {
1595 x: geom_open.x,
1596 y: geom_open.y,
1597 w: geom_open.w + geom_close.w,
1598 h: geom_close.h
1599 };
1600 self.paren_pair.draw_quad_abs(cx, geom);
1601 }
1602 else {
1603 if let Some(rc) = last.geom_open {
1604 self.paren_pair.draw_quad_abs(cx, rc);
1605 }
1606 if let Some(rc) = last.geom_close {
1607 self.paren_pair.draw_quad_abs(cx, rc);
1608 }
1609 }
1610 }
1611 };
1612 }
1613 }
1614
1615 fn draw_paren_unmatched(&mut self, cx: &mut Cx) {
1616 if !self.mark_unmatched_parens {
1617 return
1618 }
1619 while self._paren_stack.len()>0 {
1620 let last = self._paren_stack.pop().unwrap();
1621 if self.has_key_focus(cx) && !last.geom_open.is_none() {
1622 self.paren_pair.color = self.colors.paren_pair_fail;
1623 if let Some(rc) = last.geom_open {
1624 self.paren_pair.draw_quad_abs(cx, rc);
1625 }
1626 }
1627 }
1628 }
1629
1630 pub fn end_text_editor(&mut self, cx: &mut Cx, text_buffer: &TextBuffer) {
1631
1632 self.draw_new_line(cx);
1634 if !cx.is_height_computed() {
1635 cx.walk_turtle(Walk::wh(Width::Fix(0.0), Height::Fix(self._monospace_size.y)));
1636 }
1637
1638 self._text_area = self.text.end_text(cx, self._text_inst.as_ref().unwrap());
1639
1640 if self.draw_line_numbers {
1641 self.line_number_text.end_text(cx, self._line_number_inst.as_ref().unwrap());
1642 }
1643
1644 self.draw_paren_unmatched(cx);
1646 self.draw_cursors(cx);
1647 self.draw_selections(cx);
1649 self.draw_message_markers(cx, text_buffer);
1650
1651 self._final_fill_height = cx.get_height_total() - self._monospace_size.y;
1653 if !cx.is_height_computed() {
1654 cx.walk_turtle(Walk::wh(Width::Fix(0.0), Height::Fix(self._final_fill_height)));
1655 }
1656 self.do_selection_scrolling(cx, text_buffer);
1658 self.place_ime_and_draw_cursor_row(cx);
1659 self.set_indent_line_highlight_id(cx);
1660 self.draw_shadows(cx);
1661 self.bg.end_quad_fill(cx, &self._bg_inst.take().unwrap());
1662
1663 self.view.end_view(cx);
1664
1665 if self._jump_to_offset {
1666 self._jump_to_offset = false;
1667 self._scroll_pos_on_load = None;
1668 self.do_jump_to_offset(cx, text_buffer);
1669 }
1670 else if let Some(scroll_pos_on_load) = self._scroll_pos_on_load {
1671 self.view.set_scroll_pos(cx, scroll_pos_on_load);
1672 self._scroll_pos_on_load = None;
1673 }
1674 }
1675
1676 fn do_jump_to_offset(&mut self, cx: &mut Cx, text_buffer: &TextBuffer) {
1677 let offset = text_buffer.messages.jump_to_offset;
1678 self.cursors.clear_and_set_last_cursor_head_and_tail(offset, text_buffer);
1680 self.scroll_last_cursor_visible(cx, text_buffer, self._final_fill_height * 0.8);
1681 self.view.redraw_view_area(cx);
1682 }
1683
1684 fn draw_cursors(&mut self, cx: &mut Cx) {
1685 if self.has_key_focus(cx) {
1686 let origin = cx.get_turtle_origin();
1687 for rc in &self._draw_cursors.cursors {
1688 self.cursor.z = rc.z + 0.1;
1689
1690 let inst = self.cursor.draw_quad_rel(cx, Rect {x: rc.x - origin.x, y: rc.y - origin.y, w: rc.w, h: rc.h});
1691 if inst.need_uniforms_now(cx) {
1692 inst.push_uniform_float(cx, self._cursor_blink_flipflop);
1693 }
1695 }
1696 }
1697 }
1698
1699 fn draw_shadows(&mut self, cx: &mut Cx) {
1700 let gutter_width = Self::gutter_width().get(cx);
1701 self.shadow.draw_shadow_left_at(cx, Rect {
1702 x: gutter_width,
1703 y: 0.,
1704 w: 0.,
1705 h: cx.get_height_total()
1706 });
1707
1708 self.shadow.draw_shadow_top(cx);
1709 }
1710
1711 fn draw_message_markers(&mut self, cx: &mut Cx, text_buffer: &TextBuffer) {
1712 let origin = cx.get_turtle_origin();
1713 let message_markers = &mut self._draw_messages.selections;
1714
1715 for i in 0..message_markers.len() {
1716 let mark = &message_markers[i];
1717 let body = &text_buffer.messages.bodies[mark.index];
1718 self.message_marker.color = match body.level {
1719 TextBufferMessageLevel::Warning => self.colors.marker_warning,
1720 TextBufferMessageLevel::Error => self.colors.marker_error,
1721 TextBufferMessageLevel::Log => self.colors.marker_log,
1722 };
1723 self.message_marker.draw_quad_rel(cx, Rect {x: mark.rc.x - origin.x, y: mark.rc.y - origin.y, w: mark.rc.w, h: mark.rc.h});
1724 }
1725 }
1726
1727 fn draw_selections(&mut self, cx: &mut Cx) {
1728 let origin = cx.get_turtle_origin();
1729 let sel = &mut self._draw_cursors.selections;
1730 for i in 0..sel.len() {
1732 let cur = &sel[i];
1733
1734 let mk_inst = self.selection.draw_quad_rel(cx, Rect {x: cur.rc.x - origin.x, y: cur.rc.y - origin.y, w: cur.rc.w, h: cur.rc.h});
1735
1736 if i > 0 && sel[i - 1].index == cur.index {
1738 let p_rc = &sel[i - 1].rc;
1739 mk_inst.push_vec2(cx, Vec2 {x: p_rc.x - cur.rc.x, y: p_rc.w});
1740 }
1742 else {
1743 mk_inst.push_vec2(cx, Vec2 {x: 0., y: -1.});
1744 }
1746 if i < sel.len() - 1 && sel[i + 1].index == cur.index {
1748 let n_rc = &sel[i + 1].rc;
1749 mk_inst.push_vec2(cx, Vec2 {x: n_rc.x - cur.rc.x, y: n_rc.w});
1750 }
1752 else {
1753 mk_inst.push_vec2(cx, Vec2 {x: 0., y: -1.});
1754 }
1756 }
1757 }
1758
1759 fn place_ime_and_draw_cursor_row(&mut self, cx: &mut Cx) {
1760 if let Some(last_cursor) = self._draw_cursors.last_cursor {
1762 let rc = self._draw_cursors.cursors[last_cursor];
1763 if let Some(_) = self.cursors.get_last_cursor_singular() {
1764 if self.draw_cursor_row {
1766 self.cursor_row.draw_quad_abs(cx, Rect {
1767 x: self.line_number_width + cx.get_turtle_origin().x,
1768 y: rc.y,
1769 w: cx.get_width_total().max(cx.get_turtle_bounds().x) - self.line_number_width,
1770 h: rc.h
1771 });
1772 }
1773 }
1774 if cx.has_key_focus(self.view.get_view_area(cx)) {
1775 let scroll_pos = self.view.get_scroll_pos(cx);
1776 cx.show_text_ime(rc.x - scroll_pos.x, rc.y - scroll_pos.y);
1777 }
1778 else {
1779 cx.hide_text_ime();
1780 }
1781 }
1782 }
1783
1784 fn do_selection_scrolling(&mut self, cx: &mut Cx, text_buffer: &TextBuffer) {
1785 if let Some(select_scroll) = self._select_scroll.clone() {
1787 if let Some(grid_select_corner) = self._grid_select_corner {
1788 let pos = self.compute_grid_text_pos_from_abs(cx, select_scroll.abs);
1790 self.cursors.grid_select(grid_select_corner, pos, text_buffer);
1791 }
1792 else {
1793 let offset = self.text.find_closest_offset(cx, &self._text_area, select_scroll.abs);
1794 self.cursors.set_last_cursor_head(offset, text_buffer);
1795 }
1796 if select_scroll.at_end {
1797 self._select_scroll = None;
1798 }
1799 self.view.redraw_view_area(cx);
1800 }
1801 }
1802
1803 fn _do_selection_animations(&mut self, cx: &mut Cx) {
1804 if !self._anim_folding.state.is_animating() {
1805 let sel = &mut self._draw_cursors.selections;
1806
1807 let mut anim_select_any = false;
1808 for i in 0..sel.len() {
1809 let cur = &mut sel[i];
1810 let start_time = if self._select_scroll.is_none() && !self._last_finger_move.is_none() {1.}else {0.};
1811 if i < self._anim_select.len() && cur.rc.y < self._anim_select[i].ypos {
1813 self._anim_select.insert(i, AnimSelect {time: start_time, invert: true, ypos: cur.rc.y});
1815 }
1816 let (wtime, htime, invert) = if i < self._anim_select.len() {
1817 let len = self._anim_select.len() - 1;
1818 let anim = &mut self._anim_select[i];
1819 anim.ypos = cur.rc.y;
1820 if anim.time <= 0.0001 {
1821 anim.time = 0.0
1822 }
1823 else {
1824 anim.time = anim.time * 0.55;
1825 anim_select_any = true;
1827 }
1828 if i == len {
1829 (anim.time, anim.time, i == 0 && anim.invert)
1830 }
1831 else {
1832 (anim.time, 0., i == 0 && anim.invert)
1833 }
1834 }
1835 else {
1836 self._anim_select.push(AnimSelect {time: start_time, invert: i == 0, ypos: cur.rc.y});
1837 anim_select_any = true;
1838 (start_time, start_time, false)
1839 };
1840 let wtime = 1.0 - wtime as f32;
1841 let htime = 1.0 - htime as f32;
1842
1843 if invert {
1844 cur.rc.w = cur.rc.w * wtime;
1845 cur.rc.h = cur.rc.h * htime;
1846 }
1847 else {
1848 cur.rc.x = cur.rc.x + (cur.rc.w * (1. - wtime));
1849 cur.rc.w = cur.rc.w * wtime;
1850 cur.rc.h = cur.rc.h * htime;
1851 }
1852 }
1853 self._anim_select.truncate(sel.len());
1854 if anim_select_any {
1855 self.view.redraw_view_area(cx);
1856 }
1857 }
1858 }
1859
1860 fn set_indent_line_highlight_id(&mut self, cx: &mut Cx) {
1861 if let Some(indent_inst) = self._indent_line_inst {
1863 let indent_id = if self.cursors.is_last_cursor_singular() && self._last_cursor_pos.row < self._line_geometry.len() {
1864 self._line_geometry[self._last_cursor_pos.row].indent_id
1865 }else {0.};
1866 let area: Area = indent_inst.clone().into();
1867 area.write_uniform_float(cx, Self::uniform_indent_sel(), indent_id);
1868 }
1869 }
1870
1871 fn set_font_scale(&mut self, _cx: &Cx, font_scale: f32) {
1873 self.text.font_scale = font_scale;
1874 self.line_number_text.font_scale = font_scale;
1875 if font_scale > self._line_largest_font {
1876 self._line_largest_font = font_scale;
1877 }
1878 self._monospace_size.x = self._monospace_base.x * self.text.text_style.font_size * font_scale;
1879 self._monospace_size.y = self._monospace_base.y * self.text.text_style.font_size * font_scale;
1880 }
1881
1882 fn scroll_last_cursor_visible(&mut self, cx: &mut Cx, text_buffer: &TextBuffer, height_pad: f32) {
1883 if self.cursors.last_cursor >= self.cursors.set.len() {
1885 panic !("LAST CURSOR INVALID");
1886 }
1887
1888 let pos = self.cursors.get_last_cursor_text_pos(text_buffer);
1889
1890 let row = pos.row.min(self._line_geometry.len() - 1);
1892 if row < self._line_geometry.len() {
1893 let geom = &self._line_geometry[row];
1894 let mono_size = Vec2 {x: self._monospace_base.x * geom.font_size, y: self._monospace_base.y * geom.font_size};
1895 let rect = Rect {
1897 x: (pos.col as f32) * mono_size.x, y: geom.walk.y - mono_size.y * 1. - 0.5 * height_pad,
1899 w: mono_size.x * 4. + self.line_number_width,
1900 h: mono_size.y * 4. + height_pad
1901 };
1902
1903 self.view.scroll_into_view(cx, rect);
1905 }
1906 }
1907
1908 fn compute_grid_text_pos_from_abs(&mut self, cx: &Cx, abs: Vec2) -> TextPos {
1909 let rel = self.view.get_view_area(cx).abs_to_rel(cx, abs);
1911 let mut mono_size = Vec2::default();
1912 for (row, geom) in self._line_geometry.iter().enumerate() {
1913 mono_size = Vec2 {x: self._monospace_base.x * geom.font_size, y: self._monospace_base.y * geom.font_size};
1915 if rel.y < geom.walk.y || rel.y >= geom.walk.y && rel.y <= geom.walk.y + mono_size.y { let col = ((rel.x - self.line_number_width).max(0.) / mono_size.x) as usize;
1917 return TextPos {row: row, col: col};
1919 }
1920 }
1921 TextPos {row: self._line_geometry.len() - 1, col: (rel.x.max(0.) / mono_size.x) as usize}
1923 }
1924
1925 fn compute_offset_from_ypos(&mut self, cx: &Cx, ypos_abs: f32, text_buffer: &TextBuffer, end: bool) -> usize {
1926 let rel = self.view.get_view_area(cx).abs_to_rel(cx, Vec2 {x: 0.0, y: ypos_abs});
1927 let mut mono_size;
1928 let end_col = if end {1 << 31}else {0};
1930 for (row, geom) in self._line_geometry.iter().enumerate() {
1931 mono_size = Vec2 {x: self._monospace_base.x * geom.font_size, y: self._monospace_base.y * geom.font_size};
1933 if rel.y < geom.walk.y || rel.y >= geom.walk.y && rel.y <= geom.walk.y + mono_size.y { return text_buffer.text_pos_to_offset(TextPos {row: row, col: end_col})
1935 }
1936 }
1937 return text_buffer.text_pos_to_offset(TextPos {row: self._line_geometry.len() - 1, col: end_col})
1938 }
1939
1940 fn start_code_folding(&mut self, cx: &mut Cx, text_buffer: &TextBuffer) {
1941 let speed = 0.98;
1943 self._anim_folding.state.do_folding(speed, 0.95);
1947 self._anim_folding.focussed_line = self.compute_focussed_line_for_folding(cx, text_buffer);
1948 self.view.redraw_view_area(cx);
1950 }
1951
1952 fn start_code_unfolding(&mut self, cx: &mut Cx, text_buffer: &TextBuffer) {
1953 let speed = 0.96;
1954 self._anim_folding.state.do_opening(speed, 0.97);
1955 self._anim_folding.focussed_line = self.compute_focussed_line_for_folding(cx, text_buffer);
1956 self.view.redraw_view_area(cx);
1958 }
1960
1961 fn check_select_scroll_dynamics(&mut self, fe: &FingerMoveEvent) -> bool {
1962 let pow_scale = 0.1;
1963 let pow_fac = 3.;
1964 let max_speed = 40.;
1965 let pad_scroll = 20.;
1966 let rect = Rect {
1967 x: fe.rect.x + pad_scroll,
1968 y: fe.rect.y + pad_scroll,
1969 w: fe.rect.w - 2. * pad_scroll,
1970 h: fe.rect.h - 2. * pad_scroll,
1971 };
1972 let delta = Vec2 {
1973 x: if fe.abs.x < rect.x {
1974 -((rect.x - fe.abs.x) * pow_scale).powf(pow_fac).min(max_speed)
1975 }
1976 else if fe.abs.x > rect.x + rect.w {
1977 ((fe.abs.x - (rect.x + rect.w)) * pow_scale).powf(pow_fac).min(max_speed)
1978 }
1979 else {
1980 0.
1981 },
1982 y: if fe.abs.y < rect.y {
1983 -((rect.y - fe.abs.y) * pow_scale).powf(pow_fac).min(max_speed)
1984 }
1985 else if fe.abs.y > rect.y + rect.h {
1986 ((fe.abs.y - (rect.y + rect.h)) * pow_scale).powf(pow_fac).min(max_speed)
1987 }
1988 else {
1989 0.
1990 }
1991 };
1992 let last_scroll_none = self._select_scroll.is_none();
1993 if delta.x != 0. || delta.y != 0. {
1994 self._select_scroll = Some(SelectScroll {
1995 abs: fe.abs,
1996 delta: delta,
1997 at_end: false
1998 });
1999 }
2000 else {
2001 self._select_scroll = None;
2002 }
2003 last_scroll_none
2004 }
2005
2006 fn compute_next_unfolded_line_up(&self, text_buffer: &TextBuffer) -> usize {
2007 let pos = self.cursors.get_last_cursor_text_pos(text_buffer);
2008 let mut delta = 1;
2009 if pos.row > 0 && pos.row < self._line_geometry.len() {
2010 let mut scan = pos.row - 1;
2011 while scan >0 {
2012 if !self._line_geometry[scan].was_folded {
2013 delta = pos.row - scan;
2014 break;
2015 }
2016 scan -= 1;
2017 }
2018 };
2019 delta
2020 }
2021
2022 fn compute_next_unfolded_line_down(&self, text_buffer: &TextBuffer) -> usize {
2023 let pos = self.cursors.get_last_cursor_text_pos(text_buffer);
2024 let mut delta = 1;
2025 let mut scan = pos.row + 1;
2026 while scan < self._line_geometry.len() {
2027 if !self._line_geometry[scan].was_folded {
2028 delta = scan - pos.row;
2029 break;
2030 }
2031 scan += 1;
2032 }
2033 delta
2034 }
2035
2036
2037 fn compute_focussed_line_for_folding(&self, cx: &Cx, text_buffer: &TextBuffer) -> usize {
2038 let scroll = self.view.get_scroll_pos(cx);
2039 let rect = self.view.get_view_area(cx).get_rect(cx);
2040
2041 let pos = self.cursors.get_last_cursor_text_pos(text_buffer);
2043 if pos.row < self._line_geometry.len() {
2044 let geom = &self._line_geometry[pos.row];
2045 if geom.walk.y - scroll.y > 0. && geom.walk.y - scroll.y <rect.h { return pos.row
2049 }
2050 }
2051
2052 let scroll = self.view.get_scroll_pos(cx);
2054 let center_y = rect.h * 0.5 + scroll.y;
2055 for (line, geom) in self._line_geometry.iter().enumerate() {
2056 if geom.walk.y > center_y {
2057 return line
2059 }
2060 }
2061
2062 for (line, geom) in self._line_geometry.iter().enumerate() {
2064 if geom.walk.y > scroll.y {
2065 return line
2067 }
2068 }
2069
2070 return 0
2072 }
2073
2074
2075}
2076
2077#[derive(Clone)]
2078pub enum AnimFoldingState {
2079 Open,
2080 Opening(f32, f32, f32),
2081 Folded,
2082 Folding(f32, f32, f32)
2083}
2084
2085#[derive(Clone)]
2086pub struct AnimFolding {
2087 pub state: AnimFoldingState,
2088 pub focussed_line: usize,
2089 pub did_animate: bool
2090}
2091
2092#[derive(Clone)]
2093pub struct AnimSelect {
2094 pub ypos: f32,
2095 pub invert: bool,
2096 pub time: f64
2097}
2098
2099#[derive(Clone, Default)]
2100pub struct LineGeom {
2101 walk: Vec2,
2102 was_folded: bool,
2103 font_size: f32,
2104 indent_id: f32
2105}
2106
2107#[derive(Clone, Default)]
2108pub struct SelectScroll {
2109 pub delta: Vec2,
2111 pub abs: Vec2,
2112 pub at_end: bool
2113}
2114
2115#[derive(Clone)]
2116pub struct ParenItem {
2117 pair_start: usize,
2118 geom_open: Option<Rect>,
2119 geom_close: Option<Rect>,
2120 marked: bool,
2121 exp_paren: char
2122}
2123
2124impl AnimFoldingState {
2125 fn is_animating(&self) -> bool {
2126 match self {
2127 AnimFoldingState::Open => false,
2128 AnimFoldingState::Folded => false,
2129 _ => true
2130 }
2131 }
2132
2133 fn is_folded(&self) -> bool {
2134 match self {
2135 AnimFoldingState::Folded => true,
2136 AnimFoldingState::Folding(_, _, _) => true,
2137 _ => false
2138 }
2139 }
2140
2141 fn get_font_size(&self, open_size: f32, folded_size: f32) -> f32 {
2142 match self {
2143 AnimFoldingState::Open => open_size,
2144 AnimFoldingState::Folded => folded_size,
2145 AnimFoldingState::Opening(f, _, _) => f * folded_size + (1. - f) * open_size,
2146 AnimFoldingState::Folding(f, _, _) => f * open_size + (1. - f) * folded_size,
2147 }
2148 }
2149
2150 fn do_folding(&mut self, speed: f32, speed2: f32) {
2151 *self = match self {
2152 AnimFoldingState::Open => AnimFoldingState::Folding(1.0, speed, speed2),
2153 AnimFoldingState::Folded => AnimFoldingState::Folded,
2154 AnimFoldingState::Opening(f, _, _) => AnimFoldingState::Folding(1.0 - *f, speed, speed2),
2155 AnimFoldingState::Folding(f, _, _) => AnimFoldingState::Folding(*f, speed, speed2),
2156 }
2157 }
2158
2159 fn do_opening(&mut self, speed: f32, speed2: f32) {
2160 *self = match self {
2161 AnimFoldingState::Open => AnimFoldingState::Open,
2162 AnimFoldingState::Folded => AnimFoldingState::Opening(1.0, speed, speed2),
2163 AnimFoldingState::Opening(f, _, _) => AnimFoldingState::Opening(*f, speed, speed2),
2164 AnimFoldingState::Folding(f, _, _) => AnimFoldingState::Opening(1.0 - *f, speed, speed2),
2165 }
2166 }
2167
2168 fn next_anim_step(&mut self) {
2169 *self = match self {
2170 AnimFoldingState::Open => AnimFoldingState::Open,
2171 AnimFoldingState::Folded => AnimFoldingState::Folded,
2172 AnimFoldingState::Opening(f, speed, speed2) => {
2173 let new_f = *f * *speed;
2174 if new_f < 0.001 {
2175 AnimFoldingState::Open
2176 }
2177 else {
2178 AnimFoldingState::Opening(new_f, *speed * *speed2, *speed2)
2179 }
2180 },
2181 AnimFoldingState::Folding(f, speed, speed2) => {
2182 let new_f = *f * *speed;
2183 if new_f < 0.001 {
2184 AnimFoldingState::Folded
2185 }
2186 else {
2187 AnimFoldingState::Folding(new_f, *speed * *speed2, *speed2)
2188 }
2189 },
2190 }
2191 }
2192}
2193