WIP on rebuilding with extracted UI framework

This commit is contained in:
Nathan Sobo 2021-03-18 13:13:31 -06:00
parent 356bc41752
commit 23308e17a9
33 changed files with 2673 additions and 657 deletions

View file

@ -1,24 +1,15 @@
use super::{BufferView, DisplayPoint, SelectAction};
use crate::{
app::{AppContext, MutableAppContext, ViewHandle},
fonts::FontCache,
text_layout::{self, LayoutCache},
ui::{
AfterLayoutContext, Bump, Element, Event, EventContext, LayoutContext, PaintContext,
SizeConstraint,
use gpui::{
geometry::{
rect::RectF,
vector::{vec2f, Vector2F},
},
text_layout::{self, TextLayoutCache},
AfterLayoutContext, AppContext, Element, Event, EventContext, FontCache, LayoutContext,
MutableAppContext, PaintContext, Scene, SizeConstraint, ViewHandle,
};
use pathfinder_canvas::{
ArcDirection, CanvasRenderingContext2D, ColorF, FillRule, FillStyle, Path2D,
};
use pathfinder_color::ColorU;
use pathfinder_geometry::{
rect::RectF,
vector::{vec2f, Vector2F},
};
use smallvec::SmallVec;
use std::{
cmp::{self, Ordering},
cmp::{self},
sync::Arc,
};
@ -176,166 +167,165 @@ impl BufferElement {
}
fn paint_gutter(&mut self, rect: RectF, ctx: &mut PaintContext, app: &AppContext) {
if let Some(layout) = self.layout.as_ref() {
let view = self.view.as_ref(app);
let canvas = &mut ctx.canvas;
let font_cache = &ctx.font_cache;
let line_height = view.line_height(font_cache);
let scroll_top = view.scroll_position().y() * line_height;
// if let Some(layout) = self.layout.as_ref() {
// let view = self.view.as_ref(app);
// let scene = &mut ctx.scene;
// let font_cache = &ctx.font_cache;
// let line_height = view.line_height(font_cache);
// let scroll_top = view.scroll_position().y() * line_height;
canvas.save();
canvas.translate(rect.origin());
canvas.set_fill_style(FillStyle::Color(ColorU::white()));
// scene.save();
// scene.translate(rect.origin());
// scene.set_fill_style(FillStyle::Color(ColorU::white()));
let rect = RectF::new(Vector2F::zero(), rect.size());
let mut rect_path = Path2D::new();
rect_path.rect(rect);
canvas.clip_path(rect_path, FillRule::EvenOdd);
canvas.fill_rect(rect);
// let rect = RectF::new(Vector2F::zero(), rect.size());
// let mut rect_path = Path2D::new();
// rect_path.rect(rect);
// scene.clip_path(rect_path, FillRule::EvenOdd);
// scene.fill_rect(rect);
for (ix, line) in layout.line_number_layouts.iter().enumerate() {
let line_origin = vec2f(
rect.width() - line.width - layout.gutter_padding,
ix as f32 * line_height - (scroll_top % line_height),
);
line.paint(
line_origin,
rect,
&[(0..line.len, ColorU::black())],
canvas,
font_cache,
);
}
// for (ix, line) in layout.line_number_layouts.iter().enumerate() {
// let line_origin = vec2f(
// rect.width() - line.width - layout.gutter_padding,
// ix as f32 * line_height - (scroll_top % line_height),
// );
// line.paint(
// line_origin,
// rect,
// &[(0..line.len, ColorU::black())],
// scene,
// font_cache,
// );
// }
canvas.restore();
}
// scene.restore();
// }
}
fn paint_text(&mut self, rect: RectF, ctx: &mut PaintContext, app: &AppContext) {
if let Some(layout) = self.layout.as_ref() {
let canvas = &mut ctx.canvas;
let font_cache = &ctx.font_cache;
// if let Some(layout) = self.layout.as_ref() {
// let scene = &mut ctx.scene;
// let font_cache = &ctx.font_cache;
canvas.save();
canvas.translate(rect.origin());
canvas.set_fill_style(FillStyle::Color(ColorU::white()));
let rect = RectF::new(Vector2F::zero(), rect.size());
let mut rect_path = Path2D::new();
rect_path.rect(rect);
canvas.clip_path(rect_path, FillRule::EvenOdd);
canvas.fill_rect(rect);
// scene.save();
// scene.translate(rect.origin());
// scene.set_fill_style(FillStyle::Color(ColorU::white()));
// let rect = RectF::new(Vector2F::zero(), rect.size());
// let mut rect_path = Path2D::new();
// rect_path.rect(rect);
// scene.clip_path(rect_path, FillRule::EvenOdd);
// scene.fill_rect(rect);
let view = self.view.as_ref(app);
let line_height = view.line_height(font_cache);
let descent = view.font_descent(font_cache);
let start_row = view.scroll_position().y() as u32;
let scroll_top = view.scroll_position().y() * line_height;
let end_row = ((scroll_top + rect.height()) / line_height).ceil() as u32 + 1; // Add 1 to ensure selections bleed off screen
let max_glyph_width = view.em_width(font_cache);
let scroll_left = view.scroll_position().x() * max_glyph_width;
// let view = self.view.as_ref(app);
// let line_height = view.line_height(font_cache);
// let descent = view.font_descent(font_cache);
// let start_row = view.scroll_position().y() as u32;
// let scroll_top = view.scroll_position().y() * line_height;
// let end_row = ((scroll_top + rect.height()) / line_height).ceil() as u32 + 1; // Add 1 to ensure selections bleed off screen
// let max_glyph_width = view.em_width(font_cache);
// let scroll_left = view.scroll_position().x() * max_glyph_width;
// Draw selections
canvas.save();
let corner_radius = 2.5;
let mut cursors = SmallVec::<[Cursor; 32]>::new();
// // Draw selections
// scene.save();
// let corner_radius = 2.5;
// let mut cursors = SmallVec::<[Cursor; 32]>::new();
for selection in view.selections_in_range(
DisplayPoint::new(start_row, 0)..DisplayPoint::new(end_row, 0),
app,
) {
if selection.start != selection.end {
let range_start = cmp::min(selection.start, selection.end);
let range_end = cmp::max(selection.start, selection.end);
let row_range = if range_end.column() == 0 {
cmp::max(range_start.row(), start_row)..cmp::min(range_end.row(), end_row)
} else {
cmp::max(range_start.row(), start_row)
..cmp::min(range_end.row() + 1, end_row)
};
// for selection in view.selections_in_range(
// DisplayPoint::new(start_row, 0)..DisplayPoint::new(end_row, 0),
// app,
// ) {
// if selection.start != selection.end {
// let range_start = cmp::min(selection.start, selection.end);
// let range_end = cmp::max(selection.start, selection.end);
// let row_range = if range_end.column() == 0 {
// cmp::max(range_start.row(), start_row)..cmp::min(range_end.row(), end_row)
// } else {
// cmp::max(range_start.row(), start_row)
// ..cmp::min(range_end.row() + 1, end_row)
// };
let selection = Selection {
line_height,
start_y: row_range.start as f32 * line_height - scroll_top,
lines: row_range
.into_iter()
.map(|row| {
let line_layout = &layout.line_layouts[(row - start_row) as usize];
SelectionLine {
start_x: if row == range_start.row() {
line_layout.x_for_index(range_start.column() as usize)
- scroll_left
- descent
} else {
-scroll_left
},
end_x: if row == range_end.row() {
line_layout.x_for_index(range_end.column() as usize)
- scroll_left
- descent
} else {
line_layout.width + corner_radius * 2.0
- scroll_left
- descent
},
}
})
.collect(),
};
// let selection = Selection {
// line_height,
// start_y: row_range.start as f32 * line_height - scroll_top,
// lines: row_range
// .into_iter()
// .map(|row| {
// let line_layout = &layout.line_layouts[(row - start_row) as usize];
// SelectionLine {
// start_x: if row == range_start.row() {
// line_layout.x_for_index(range_start.column() as usize)
// - scroll_left
// - descent
// } else {
// -scroll_left
// },
// end_x: if row == range_end.row() {
// line_layout.x_for_index(range_end.column() as usize)
// - scroll_left
// - descent
// } else {
// line_layout.width + corner_radius * 2.0
// - scroll_left
// - descent
// },
// }
// })
// .collect(),
// };
selection.paint(canvas);
}
// selection.paint(scene);
// }
if view.cursors_visible() {
let cursor_position = selection.end;
if (start_row..end_row).contains(&cursor_position.row()) {
let cursor_row_layout =
&layout.line_layouts[(selection.end.row() - start_row) as usize];
cursors.push(Cursor {
x: cursor_row_layout.x_for_index(selection.end.column() as usize)
- scroll_left
- descent,
y: selection.end.row() as f32 * line_height - scroll_top,
line_height,
});
}
}
}
canvas.restore();
// if view.cursors_visible() {
// let cursor_position = selection.end;
// if (start_row..end_row).contains(&cursor_position.row()) {
// let cursor_row_layout =
// &layout.line_layouts[(selection.end.row() - start_row) as usize];
// cursors.push(Cursor {
// x: cursor_row_layout.x_for_index(selection.end.column() as usize)
// - scroll_left
// - descent,
// y: selection.end.row() as f32 * line_height - scroll_top,
// line_height,
// });
// }
// }
// }
// scene.restore();
// Draw glyphs
// // Draw glyphs
canvas.set_fill_style(FillStyle::Color(ColorU::black()));
// scene.set_fill_style(FillStyle::Color(ColorU::black()));
for (ix, line) in layout.line_layouts.iter().enumerate() {
let row = start_row + ix as u32;
let line_origin = vec2f(
-scroll_left - descent,
row as f32 * line_height - scroll_top,
);
// for (ix, line) in layout.line_layouts.iter().enumerate() {
// let row = start_row + ix as u32;
// let line_origin = vec2f(
// -scroll_left - descent,
// row as f32 * line_height - scroll_top,
// );
line.paint(
line_origin,
rect,
&[(0..line.len, ColorU::black())],
canvas,
font_cache,
);
}
// line.paint(
// line_origin,
// rect,
// &[(0..line.len, ColorU::black())],
// scene,
// font_cache,
// );
// }
for cursor in cursors {
cursor.paint(canvas);
}
// for cursor in cursors {
// cursor.paint(scene);
// }
canvas.restore()
}
// scene.restore()
// }
}
}
impl<'a> Element<'a> for BufferElement {
impl Element for BufferElement {
fn layout(
&mut self,
constraint: SizeConstraint,
_: &'a Bump,
ctx: &mut LayoutContext,
app: &AppContext,
) -> Vector2F {
@ -480,7 +470,7 @@ impl<'a> Element<'a> for BufferElement {
}
}
fn size(&self) -> Option<pathfinder_canvas::Vector2F> {
fn size(&self) -> Option<Vector2F> {
self.layout.as_ref().map(|layout| layout.size)
}
}
@ -501,7 +491,7 @@ impl LayoutState {
&self,
view: &BufferView,
font_cache: &FontCache,
layout_cache: &LayoutCache,
layout_cache: &TextLayoutCache,
app: &AppContext,
) -> f32 {
let row = view.rightmost_point(app).row();
@ -516,7 +506,7 @@ impl LayoutState {
&self,
view: &BufferView,
font_cache: &FontCache,
layout_cache: &LayoutCache,
layout_cache: &TextLayoutCache,
app: &AppContext,
) -> Vector2F {
vec2f(
@ -569,12 +559,12 @@ struct Cursor {
}
impl Cursor {
fn paint(&self, canvas: &mut CanvasRenderingContext2D) {
canvas.set_fill_style(FillStyle::Color(ColorU::black()));
canvas.fill_rect(RectF::new(
vec2f(self.x, self.y),
vec2f(2.0, self.line_height),
));
fn paint(&self, scene: &mut Scene) {
// scene.set_fill_style(FillStyle::Color(ColorU::black()));
// scene.fill_rect(RectF::new(
// vec2f(self.x, self.y),
// vec2f(2.0, self.line_height),
// ));
}
}
@ -592,167 +582,84 @@ struct SelectionLine {
}
impl Selection {
fn paint(&self, canvas: &mut CanvasRenderingContext2D) {
fn paint(&self, scene: &mut Scene) {
if self.lines.len() >= 2 && self.lines[0].start_x > self.lines[1].end_x {
self.paint_lines(self.start_y, &self.lines[0..1], canvas);
self.paint_lines(self.start_y + self.line_height, &self.lines[1..], canvas);
self.paint_lines(self.start_y, &self.lines[0..1], scene);
self.paint_lines(self.start_y + self.line_height, &self.lines[1..], scene);
} else {
self.paint_lines(self.start_y, &self.lines, canvas);
self.paint_lines(self.start_y, &self.lines, scene);
}
}
fn paint_lines(
&self,
start_y: f32,
lines: &[SelectionLine],
canvas: &mut CanvasRenderingContext2D,
) {
use Direction::*;
fn paint_lines(&self, start_y: f32, lines: &[SelectionLine], scene: &mut Scene) {
// use Direction::*;
if lines.is_empty() {
return;
}
// if lines.is_empty() {
// return;
// }
let mut path = Path2D::new();
let corner_radius = 0.08 * self.line_height;
// let mut path = Path2D::new();
// let corner_radius = 0.08 * self.line_height;
let first_line = lines.first().unwrap();
let last_line = lines.last().unwrap();
// let first_line = lines.first().unwrap();
// let last_line = lines.last().unwrap();
let corner = vec2f(first_line.end_x, start_y);
path.move_to(corner - vec2f(corner_radius, 0.0));
rounded_corner(&mut path, corner, corner_radius, Right, Down);
// let corner = vec2f(first_line.end_x, start_y);
// path.move_to(corner - vec2f(corner_radius, 0.0));
// rounded_corner(&mut path, corner, corner_radius, Right, Down);
let mut iter = lines.iter().enumerate().peekable();
while let Some((ix, line)) = iter.next() {
let corner = vec2f(line.end_x, start_y + (ix + 1) as f32 * self.line_height);
// let mut iter = lines.iter().enumerate().peekable();
// while let Some((ix, line)) = iter.next() {
// let corner = vec2f(line.end_x, start_y + (ix + 1) as f32 * self.line_height);
if let Some((_, next_line)) = iter.peek() {
let next_corner = vec2f(next_line.end_x, corner.y());
// if let Some((_, next_line)) = iter.peek() {
// let next_corner = vec2f(next_line.end_x, corner.y());
match next_corner.x().partial_cmp(&corner.x()).unwrap() {
Ordering::Equal => {
path.line_to(corner);
}
Ordering::Less => {
path.line_to(corner - vec2f(0.0, corner_radius));
rounded_corner(&mut path, corner, corner_radius, Down, Left);
path.line_to(next_corner + vec2f(corner_radius, 0.0));
rounded_corner(&mut path, next_corner, corner_radius, Left, Down);
}
Ordering::Greater => {
path.line_to(corner - vec2f(0.0, corner_radius));
rounded_corner(&mut path, corner, corner_radius, Down, Right);
path.line_to(next_corner - vec2f(corner_radius, 0.0));
rounded_corner(&mut path, next_corner, corner_radius, Right, Down);
}
}
} else {
path.line_to(corner - vec2f(0.0, corner_radius));
rounded_corner(&mut path, corner, corner_radius, Down, Left);
// match next_corner.x().partial_cmp(&corner.x()).unwrap() {
// Ordering::Equal => {
// path.line_to(corner);
// }
// Ordering::Less => {
// path.line_to(corner - vec2f(0.0, corner_radius));
// rounded_corner(&mut path, corner, corner_radius, Down, Left);
// path.line_to(next_corner + vec2f(corner_radius, 0.0));
// rounded_corner(&mut path, next_corner, corner_radius, Left, Down);
// }
// Ordering::Greater => {
// path.line_to(corner - vec2f(0.0, corner_radius));
// rounded_corner(&mut path, corner, corner_radius, Down, Right);
// path.line_to(next_corner - vec2f(corner_radius, 0.0));
// rounded_corner(&mut path, next_corner, corner_radius, Right, Down);
// }
// }
// } else {
// path.line_to(corner - vec2f(0.0, corner_radius));
// rounded_corner(&mut path, corner, corner_radius, Down, Left);
let corner = vec2f(line.start_x, corner.y());
path.line_to(corner + vec2f(corner_radius, 0.0));
rounded_corner(&mut path, corner, corner_radius, Left, Up);
}
}
// let corner = vec2f(line.start_x, corner.y());
// path.line_to(corner + vec2f(corner_radius, 0.0));
// rounded_corner(&mut path, corner, corner_radius, Left, Up);
// }
// }
if first_line.start_x > last_line.start_x {
let corner = vec2f(last_line.start_x, start_y + self.line_height);
path.line_to(corner + vec2f(0.0, corner_radius));
rounded_corner(&mut path, corner, corner_radius, Up, Right);
let corner = vec2f(first_line.start_x, corner.y());
path.line_to(corner - vec2f(corner_radius, 0.0));
rounded_corner(&mut path, corner, corner_radius, Right, Up);
}
// if first_line.start_x > last_line.start_x {
// let corner = vec2f(last_line.start_x, start_y + self.line_height);
// path.line_to(corner + vec2f(0.0, corner_radius));
// rounded_corner(&mut path, corner, corner_radius, Up, Right);
// let corner = vec2f(first_line.start_x, corner.y());
// path.line_to(corner - vec2f(corner_radius, 0.0));
// rounded_corner(&mut path, corner, corner_radius, Right, Up);
// }
let corner = vec2f(first_line.start_x, start_y);
path.line_to(corner + vec2f(0.0, corner_radius));
rounded_corner(&mut path, corner, corner_radius, Up, Right);
path.close_path();
// let corner = vec2f(first_line.start_x, start_y);
// path.line_to(corner + vec2f(0.0, corner_radius));
// rounded_corner(&mut path, corner, corner_radius, Up, Right);
// path.close_path();
canvas.set_fill_style(FillStyle::Color(
ColorF::new(0.639, 0.839, 1.0, 1.0).to_u8(),
));
canvas.fill_path(path, FillRule::Winding);
}
}
enum Direction {
Up,
Down,
Left,
Right,
}
fn rounded_corner(
path: &mut Path2D,
corner: Vector2F,
radius: f32,
incoming: Direction,
outgoing: Direction,
) {
use std::f32::consts::PI;
use Direction::*;
match (incoming, outgoing) {
(Down, Right) => path.arc(
corner + vec2f(radius, -radius),
radius,
1.0 * PI,
0.5 * PI,
ArcDirection::CCW,
),
(Down, Left) => path.arc(
corner + vec2f(-radius, -radius),
radius,
0.0,
0.5 * PI,
ArcDirection::CW,
),
(Up, Right) => path.arc(
corner + vec2f(radius, radius),
radius,
1.0 * PI,
1.5 * PI,
ArcDirection::CW,
),
(Up, Left) => path.arc(
corner + vec2f(-radius, radius),
radius,
0.0,
1.5 * PI,
ArcDirection::CCW,
),
(Right, Up) => path.arc(
corner + vec2f(-radius, -radius),
radius,
0.5 * PI,
0.0,
ArcDirection::CCW,
),
(Right, Down) => path.arc(
corner + vec2f(-radius, radius),
radius,
1.5 * PI,
2.0 * PI,
ArcDirection::CW,
),
(Left, Up) => path.arc(
corner + vec2f(radius, -radius),
radius,
0.5 * PI,
PI,
ArcDirection::CW,
),
(Left, Down) => path.arc(
corner + vec2f(radius, radius),
radius,
1.5 * PI,
PI,
ArcDirection::CCW,
),
_ => panic!("invalid incoming and outgoing directions for a corner"),
// scene.set_fill_style(FillStyle::Color(
// ColorF::new(0.639, 0.839, 1.0, 1.0).to_u8(),
// ));
// scene.fill_path(path, FillRule::Winding);
}
}