mirror of
https://github.com/zed-industries/zed.git
synced 2025-01-02 18:51:34 +03:00
WIP: Render path winding numbers to stencil buffer
Co-Authored-By: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
parent
a8495d09f8
commit
0b12779e62
@ -1,31 +1,27 @@
|
|||||||
pub use pathfinder_geometry::*;
|
pub use pathfinder_geometry::*;
|
||||||
|
|
||||||
|
use super::scene::{Path, PathVertex};
|
||||||
use vector::{vec2f, Vector2F};
|
use vector::{vec2f, Vector2F};
|
||||||
|
|
||||||
pub(crate) struct Vertex {
|
pub struct PathBuilder {
|
||||||
xy_position: Vector2F,
|
vertices: Vec<PathVertex>,
|
||||||
st_position: Vector2F,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Path {
|
|
||||||
vertices: Vec<Vertex>,
|
|
||||||
start: Vector2F,
|
start: Vector2F,
|
||||||
current: Vector2F,
|
current: Vector2F,
|
||||||
countours_len: usize,
|
contour_count: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Kind {
|
enum PathVertexKind {
|
||||||
Solid,
|
Solid,
|
||||||
Quadratic,
|
Quadratic,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Path {
|
impl PathBuilder {
|
||||||
fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
vertices: Vec::new(),
|
vertices: Vec::new(),
|
||||||
start: vec2f(0., 0.),
|
start: vec2f(0., 0.),
|
||||||
current: vec2f(0., 0.),
|
current: vec2f(0., 0.),
|
||||||
countours_len: 0,
|
contour_count: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,58 +29,60 @@ impl Path {
|
|||||||
self.vertices.clear();
|
self.vertices.clear();
|
||||||
self.start = point;
|
self.start = point;
|
||||||
self.current = point;
|
self.current = point;
|
||||||
self.countours_len = 0;
|
self.contour_count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn line_to(&mut self, point: Vector2F) {
|
pub fn line_to(&mut self, point: Vector2F) {
|
||||||
self.countours_len += 1;
|
self.contour_count += 1;
|
||||||
if self.countours_len > 1 {
|
if self.contour_count > 1 {
|
||||||
self.push_triangle(self.start, self.current, point, Kind::Solid);
|
self.push_triangle(self.start, self.current, point, PathVertexKind::Solid);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.current = point;
|
self.current = point;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn curve_to(&mut self, point: Vector2F, ctrl: Vector2F) {
|
pub fn curve_to(&mut self, point: Vector2F, ctrl: Vector2F) {
|
||||||
self.countours_len += 1;
|
self.contour_count += 1;
|
||||||
if self.countours_len > 1 {
|
if self.contour_count > 1 {
|
||||||
self.push_triangle(self.start, self.current, point, Kind::Solid);
|
self.push_triangle(self.start, self.current, point, PathVertexKind::Solid);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.push_triangle(self.current, ctrl, point, Kind::Quadratic);
|
self.push_triangle(self.current, ctrl, point, PathVertexKind::Quadratic);
|
||||||
self.current = point;
|
self.current = point;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn close(self) -> Vec<Vertex> {
|
pub fn build(self) -> Path {
|
||||||
self.vertices
|
Path {
|
||||||
|
vertices: self.vertices,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_triangle(&mut self, a: Vector2F, b: Vector2F, c: Vector2F, kind: Kind) {
|
fn push_triangle(&mut self, a: Vector2F, b: Vector2F, c: Vector2F, kind: PathVertexKind) {
|
||||||
match kind {
|
match kind {
|
||||||
Kind::Solid => {
|
PathVertexKind::Solid => {
|
||||||
self.vertices.push(Vertex {
|
self.vertices.push(PathVertex {
|
||||||
xy_position: a,
|
xy_position: a,
|
||||||
st_position: vec2f(0., 1.),
|
st_position: vec2f(0., 1.),
|
||||||
});
|
});
|
||||||
self.vertices.push(Vertex {
|
self.vertices.push(PathVertex {
|
||||||
xy_position: b,
|
xy_position: b,
|
||||||
st_position: vec2f(0., 1.),
|
st_position: vec2f(0., 1.),
|
||||||
});
|
});
|
||||||
self.vertices.push(Vertex {
|
self.vertices.push(PathVertex {
|
||||||
xy_position: c,
|
xy_position: c,
|
||||||
st_position: vec2f(0., 1.),
|
st_position: vec2f(0., 1.),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Kind::Quadratic => {
|
PathVertexKind::Quadratic => {
|
||||||
self.vertices.push(Vertex {
|
self.vertices.push(PathVertex {
|
||||||
xy_position: a,
|
xy_position: a,
|
||||||
st_position: vec2f(0., 0.),
|
st_position: vec2f(0., 0.),
|
||||||
});
|
});
|
||||||
self.vertices.push(Vertex {
|
self.vertices.push(PathVertex {
|
||||||
xy_position: b,
|
xy_position: b,
|
||||||
st_position: vec2f(0.5, 0.),
|
st_position: vec2f(0.5, 0.),
|
||||||
});
|
});
|
||||||
self.vertices.push(Vertex {
|
self.vertices.push(PathVertex {
|
||||||
xy_position: c,
|
xy_position: c,
|
||||||
st_position: vec2f(1., 1.),
|
st_position: vec2f(1., 1.),
|
||||||
});
|
});
|
||||||
|
@ -22,6 +22,7 @@ const INSTANCE_BUFFER_SIZE: usize = 1024 * 1024; // This is an arbitrary decisio
|
|||||||
struct RenderContext<'a> {
|
struct RenderContext<'a> {
|
||||||
drawable_size: Vector2F,
|
drawable_size: Vector2F,
|
||||||
command_encoder: &'a metal::RenderCommandEncoderRef,
|
command_encoder: &'a metal::RenderCommandEncoderRef,
|
||||||
|
command_buffer: &'a metal::CommandBufferRef,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Renderer {
|
pub struct Renderer {
|
||||||
@ -29,9 +30,10 @@ pub struct Renderer {
|
|||||||
quad_pipeline_state: metal::RenderPipelineState,
|
quad_pipeline_state: metal::RenderPipelineState,
|
||||||
shadow_pipeline_state: metal::RenderPipelineState,
|
shadow_pipeline_state: metal::RenderPipelineState,
|
||||||
sprite_pipeline_state: metal::RenderPipelineState,
|
sprite_pipeline_state: metal::RenderPipelineState,
|
||||||
|
path_winding_pipeline_state: metal::RenderPipelineState,
|
||||||
unit_vertices: metal::Buffer,
|
unit_vertices: metal::Buffer,
|
||||||
instances: metal::Buffer,
|
instances: metal::Buffer,
|
||||||
paths_texture: metal::Texture,
|
path_winding_texture: metal::Texture,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Renderer {
|
impl Renderer {
|
||||||
@ -64,10 +66,12 @@ impl Renderer {
|
|||||||
|
|
||||||
let paths_texture_size = vec2f(2048., 2048.);
|
let paths_texture_size = vec2f(2048., 2048.);
|
||||||
let descriptor = metal::TextureDescriptor::new();
|
let descriptor = metal::TextureDescriptor::new();
|
||||||
descriptor.set_pixel_format(metal::MTLPixelFormat::A8Unorm);
|
descriptor.set_pixel_format(metal::MTLPixelFormat::Stencil8);
|
||||||
descriptor.set_width(paths_texture_size.x() as u64);
|
descriptor.set_width(paths_texture_size.x() as u64);
|
||||||
descriptor.set_height(paths_texture_size.y() as u64);
|
descriptor.set_height(paths_texture_size.y() as u64);
|
||||||
let paths_texture = device.new_texture(&descriptor);
|
descriptor.set_usage(metal::MTLTextureUsage::RenderTarget);
|
||||||
|
descriptor.set_storage_mode(metal::MTLStorageMode::Private);
|
||||||
|
let path_winding_texture = device.new_texture(&descriptor);
|
||||||
|
|
||||||
let atlas_size: Vector2I = vec2i(1024, 768);
|
let atlas_size: Vector2I = vec2i(1024, 768);
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
@ -96,9 +100,17 @@ impl Renderer {
|
|||||||
"sprite_fragment",
|
"sprite_fragment",
|
||||||
pixel_format,
|
pixel_format,
|
||||||
)?,
|
)?,
|
||||||
|
path_winding_pipeline_state: build_stencil_pipeline_state(
|
||||||
|
&device,
|
||||||
|
&library,
|
||||||
|
"path_winding",
|
||||||
|
"path_winding_vertex",
|
||||||
|
"path_winding_fragment",
|
||||||
|
path_winding_texture.pixel_format(),
|
||||||
|
)?,
|
||||||
unit_vertices,
|
unit_vertices,
|
||||||
instances,
|
instances,
|
||||||
paths_texture,
|
path_winding_texture,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,12 +145,15 @@ impl Renderer {
|
|||||||
let ctx = RenderContext {
|
let ctx = RenderContext {
|
||||||
drawable_size,
|
drawable_size,
|
||||||
command_encoder,
|
command_encoder,
|
||||||
|
command_buffer,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut offset = 0;
|
let mut offset = 0;
|
||||||
for layer in scene.layers() {
|
for layer in scene.layers() {
|
||||||
self.clip(scene, layer, &ctx);
|
self.clip(scene, layer, &ctx);
|
||||||
self.render_shadows(scene, layer, &mut offset, &ctx);
|
self.render_shadows(scene, layer, &mut offset, &ctx);
|
||||||
self.render_quads(scene, layer, &mut offset, &ctx);
|
self.render_quads(scene, layer, &mut offset, &ctx);
|
||||||
|
self.render_paths(scene, layer, &mut offset, &ctx);
|
||||||
self.render_sprites(scene, layer, &mut offset, &ctx);
|
self.render_sprites(scene, layer, &mut offset, &ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -318,6 +333,66 @@ impl Renderer {
|
|||||||
offset: &mut usize,
|
offset: &mut usize,
|
||||||
ctx: &RenderContext,
|
ctx: &RenderContext,
|
||||||
) {
|
) {
|
||||||
|
for (color, paths) in layer.paths_by_color() {
|
||||||
|
let winding_render_pass_descriptor = metal::RenderPassDescriptor::new();
|
||||||
|
let stencil_attachment = winding_render_pass_descriptor.stencil_attachment().unwrap();
|
||||||
|
stencil_attachment.set_texture(Some(&self.path_winding_texture));
|
||||||
|
stencil_attachment.set_load_action(metal::MTLLoadAction::Clear);
|
||||||
|
stencil_attachment.set_store_action(metal::MTLStoreAction::Store);
|
||||||
|
let winding_command_encoder = ctx
|
||||||
|
.command_buffer
|
||||||
|
.new_render_command_encoder(winding_render_pass_descriptor);
|
||||||
|
|
||||||
|
align_offset(offset);
|
||||||
|
let vertex_count = paths.iter().map(|p| p.vertices.len()).sum::<usize>();
|
||||||
|
let next_offset = *offset + vertex_count * mem::size_of::<shaders::GPUIPathVertex>();
|
||||||
|
assert!(
|
||||||
|
next_offset <= INSTANCE_BUFFER_SIZE,
|
||||||
|
"instance buffer exhausted"
|
||||||
|
);
|
||||||
|
|
||||||
|
winding_command_encoder.set_render_pipeline_state(&self.path_winding_pipeline_state);
|
||||||
|
winding_command_encoder.set_vertex_buffer(
|
||||||
|
shaders::GPUIPathWindingVertexInputIndex_GPUIPathWindingVertexInputIndexVertices
|
||||||
|
as u64,
|
||||||
|
Some(&self.instances),
|
||||||
|
*offset as u64,
|
||||||
|
);
|
||||||
|
winding_command_encoder.set_vertex_bytes(
|
||||||
|
shaders::GPUIPathWindingVertexInputIndex_GPUIPathWindingVertexInputIndexViewportSize
|
||||||
|
as u64,
|
||||||
|
mem::size_of::<shaders::vector_float2>() as u64,
|
||||||
|
[ctx.drawable_size.to_float2()].as_ptr() as *const c_void,
|
||||||
|
);
|
||||||
|
|
||||||
|
let buffer_contents = unsafe {
|
||||||
|
(self.instances.contents() as *mut u8).offset(*offset as isize)
|
||||||
|
as *mut shaders::GPUIPathVertex
|
||||||
|
};
|
||||||
|
|
||||||
|
for (ix, vertex) in paths.iter().flat_map(|p| &p.vertices).enumerate() {
|
||||||
|
let shader_vertex = shaders::GPUIPathVertex {
|
||||||
|
xy_position: vertex.xy_position.to_float2(),
|
||||||
|
st_position: vertex.st_position.to_float2(),
|
||||||
|
};
|
||||||
|
unsafe {
|
||||||
|
*(buffer_contents.offset(ix as isize)) = shader_vertex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.instances.did_modify_range(NSRange {
|
||||||
|
location: *offset as u64,
|
||||||
|
length: (next_offset - *offset) as u64,
|
||||||
|
});
|
||||||
|
*offset = next_offset;
|
||||||
|
|
||||||
|
winding_command_encoder.draw_primitives(
|
||||||
|
metal::MTLPrimitiveType::Triangle,
|
||||||
|
0,
|
||||||
|
vertex_count as u64,
|
||||||
|
);
|
||||||
|
winding_command_encoder.end_encoding();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_sprites(
|
fn render_sprites(
|
||||||
@ -455,6 +530,32 @@ fn build_pipeline_state(
|
|||||||
.map_err(|message| anyhow!("could not create render pipeline state: {}", message))
|
.map_err(|message| anyhow!("could not create render pipeline state: {}", message))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn build_stencil_pipeline_state(
|
||||||
|
device: &metal::DeviceRef,
|
||||||
|
library: &metal::LibraryRef,
|
||||||
|
label: &str,
|
||||||
|
vertex_fn_name: &str,
|
||||||
|
fragment_fn_name: &str,
|
||||||
|
pixel_format: metal::MTLPixelFormat,
|
||||||
|
) -> Result<metal::RenderPipelineState> {
|
||||||
|
let vertex_fn = library
|
||||||
|
.get_function(vertex_fn_name, None)
|
||||||
|
.map_err(|message| anyhow!("error locating vertex function: {}", message))?;
|
||||||
|
let fragment_fn = library
|
||||||
|
.get_function(fragment_fn_name, None)
|
||||||
|
.map_err(|message| anyhow!("error locating fragment function: {}", message))?;
|
||||||
|
|
||||||
|
let descriptor = metal::RenderPipelineDescriptor::new();
|
||||||
|
descriptor.set_label(label);
|
||||||
|
descriptor.set_vertex_function(Some(vertex_fn.as_ref()));
|
||||||
|
descriptor.set_fragment_function(Some(fragment_fn.as_ref()));
|
||||||
|
descriptor.set_stencil_attachment_pixel_format(pixel_format);
|
||||||
|
|
||||||
|
device
|
||||||
|
.new_render_pipeline_state(&descriptor)
|
||||||
|
.map_err(|message| anyhow!("could not create render pipeline state: {}", message))
|
||||||
|
}
|
||||||
|
|
||||||
mod shaders {
|
mod shaders {
|
||||||
#![allow(non_upper_case_globals)]
|
#![allow(non_upper_case_globals)]
|
||||||
#![allow(non_camel_case_types)]
|
#![allow(non_camel_case_types)]
|
||||||
|
@ -53,3 +53,13 @@ typedef struct {
|
|||||||
vector_float2 atlas_origin;
|
vector_float2 atlas_origin;
|
||||||
vector_uchar4 color;
|
vector_uchar4 color;
|
||||||
} GPUISprite;
|
} GPUISprite;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
GPUIPathWindingVertexInputIndexVertices = 0,
|
||||||
|
GPUIPathWindingVertexInputIndexViewportSize = 1,
|
||||||
|
} GPUIPathWindingVertexInputIndex;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
vector_float2 xy_position;
|
||||||
|
vector_float2 st_position;
|
||||||
|
} GPUIPathVertex;
|
||||||
|
@ -201,3 +201,31 @@ fragment float4 sprite_fragment(
|
|||||||
color.a *= mask.a;
|
color.a *= mask.a;
|
||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct PathWindingFragmentInput {
|
||||||
|
float4 position [[position]];
|
||||||
|
float2 st_position;
|
||||||
|
};
|
||||||
|
|
||||||
|
vertex PathWindingFragmentInput path_winding_vertex(
|
||||||
|
uint vertex_id [[vertex_id]],
|
||||||
|
constant GPUIPathVertex *vertices [[buffer(GPUIPathWindingVertexInputIndexVertices)]],
|
||||||
|
constant float2 *viewport_size [[buffer(GPUIPathWindingVertexInputIndexViewportSize)]]
|
||||||
|
) {
|
||||||
|
GPUIPathVertex v = vertices[vertex_id];
|
||||||
|
float4 device_position = to_device_position(v.xy_position, *viewport_size);
|
||||||
|
return PathWindingFragmentInput {
|
||||||
|
device_position,
|
||||||
|
v.st_position,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment float4 path_winding_fragment(
|
||||||
|
PathWindingFragmentInput input [[stage_in]]
|
||||||
|
) {
|
||||||
|
if (input.st_position.x * input.st_position.x - input.st_position.y > 0.0) {
|
||||||
|
return float4(0.0);
|
||||||
|
} else {
|
||||||
|
return float4(float3(0.0), 1.0 / 255.0);
|
||||||
|
}
|
||||||
|
}
|
@ -16,6 +16,7 @@ pub struct Layer {
|
|||||||
quads: Vec<Quad>,
|
quads: Vec<Quad>,
|
||||||
shadows: Vec<Shadow>,
|
shadows: Vec<Shadow>,
|
||||||
glyphs: Vec<Glyph>,
|
glyphs: Vec<Glyph>,
|
||||||
|
paths: Vec<(ColorU, Vec<Path>)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
@ -53,6 +54,17 @@ pub struct Border {
|
|||||||
pub left: bool,
|
pub left: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Path {
|
||||||
|
pub vertices: Vec<PathVertex>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct PathVertex {
|
||||||
|
pub xy_position: Vector2F,
|
||||||
|
pub st_position: Vector2F,
|
||||||
|
}
|
||||||
|
|
||||||
impl Scene {
|
impl Scene {
|
||||||
pub fn new(scale_factor: f32) -> Self {
|
pub fn new(scale_factor: f32) -> Self {
|
||||||
Scene {
|
Scene {
|
||||||
@ -93,6 +105,10 @@ impl Scene {
|
|||||||
self.active_layer().push_glyph(glyph)
|
self.active_layer().push_glyph(glyph)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn push_path(&mut self, color: ColorU, path: Path) {
|
||||||
|
self.active_layer().push_path(color, path);
|
||||||
|
}
|
||||||
|
|
||||||
fn active_layer(&mut self) -> &mut Layer {
|
fn active_layer(&mut self) -> &mut Layer {
|
||||||
&mut self.layers[*self.active_layer_stack.last().unwrap()]
|
&mut self.layers[*self.active_layer_stack.last().unwrap()]
|
||||||
}
|
}
|
||||||
@ -105,6 +121,7 @@ impl Layer {
|
|||||||
quads: Vec::new(),
|
quads: Vec::new(),
|
||||||
shadows: Vec::new(),
|
shadows: Vec::new(),
|
||||||
glyphs: Vec::new(),
|
glyphs: Vec::new(),
|
||||||
|
paths: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,6 +152,17 @@ impl Layer {
|
|||||||
pub fn glyphs(&self) -> &[Glyph] {
|
pub fn glyphs(&self) -> &[Glyph] {
|
||||||
self.glyphs.as_slice()
|
self.glyphs.as_slice()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn push_path(&mut self, color: ColorU, path: Path) {
|
||||||
|
match self.paths.binary_search_by_key(&color, |(c, path)| *c) {
|
||||||
|
Err(i) => self.paths.insert(i, (color, vec![path])),
|
||||||
|
Ok(i) => self.paths[i].1.push(path),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn paths_by_color(&self) -> &[(ColorU, Vec<Path>)] {
|
||||||
|
self.paths.as_slice()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Border {
|
impl Border {
|
||||||
|
@ -4,6 +4,7 @@ use gpui::{
|
|||||||
geometry::{
|
geometry::{
|
||||||
rect::RectF,
|
rect::RectF,
|
||||||
vector::{vec2f, Vector2F},
|
vector::{vec2f, Vector2F},
|
||||||
|
PathBuilder,
|
||||||
},
|
},
|
||||||
text_layout::{self, TextLayoutCache},
|
text_layout::{self, TextLayoutCache},
|
||||||
AfterLayoutContext, AppContext, Border, Element, Event, EventContext, FontCache, LayoutContext,
|
AfterLayoutContext, AppContext, Border, Element, Event, EventContext, FontCache, LayoutContext,
|
||||||
@ -211,51 +212,51 @@ impl BufferElement {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Draw selections
|
// Draw selections
|
||||||
// let corner_radius = 2.5;
|
let corner_radius = 2.5;
|
||||||
let mut cursors = SmallVec::<[Cursor; 32]>::new();
|
let mut cursors = SmallVec::<[Cursor; 32]>::new();
|
||||||
|
|
||||||
for selection in view.selections_in_range(
|
for selection in view.selections_in_range(
|
||||||
DisplayPoint::new(start_row, 0)..DisplayPoint::new(end_row, 0),
|
DisplayPoint::new(start_row, 0)..DisplayPoint::new(end_row, 0),
|
||||||
ctx.app,
|
ctx.app,
|
||||||
) {
|
) {
|
||||||
// if selection.start != selection.end {
|
if selection.start != selection.end {
|
||||||
// let range_start = cmp::min(selection.start, selection.end);
|
let range_start = cmp::min(selection.start, selection.end);
|
||||||
// let range_end = cmp::max(selection.start, selection.end);
|
let range_end = cmp::max(selection.start, selection.end);
|
||||||
// let row_range = if range_end.column() == 0 {
|
let row_range = if range_end.column() == 0 {
|
||||||
// cmp::max(range_start.row(), start_row)..cmp::min(range_end.row(), end_row)
|
cmp::max(range_start.row(), start_row)..cmp::min(range_end.row(), end_row)
|
||||||
// } else {
|
} else {
|
||||||
// cmp::max(range_start.row(), start_row)..cmp::min(range_end.row() + 1, end_row)
|
cmp::max(range_start.row(), start_row)..cmp::min(range_end.row() + 1, end_row)
|
||||||
// };
|
};
|
||||||
|
|
||||||
// let selection = Selection {
|
let selection = Selection {
|
||||||
// line_height,
|
line_height,
|
||||||
// start_y: row_range.start as f32 * line_height - scroll_top,
|
start_y: row_range.start as f32 * line_height - scroll_top,
|
||||||
// lines: row_range
|
lines: row_range
|
||||||
// .into_iter()
|
.into_iter()
|
||||||
// .map(|row| {
|
.map(|row| {
|
||||||
// let line_layout = &layout.line_layouts[(row - start_row) as usize];
|
let line_layout = &layout.line_layouts[(row - start_row) as usize];
|
||||||
// SelectionLine {
|
SelectionLine {
|
||||||
// start_x: if row == range_start.row() {
|
start_x: if row == range_start.row() {
|
||||||
// line_layout.x_for_index(range_start.column() as usize)
|
line_layout.x_for_index(range_start.column() as usize)
|
||||||
// - scroll_left
|
- scroll_left
|
||||||
// - descent
|
- descent
|
||||||
// } else {
|
} else {
|
||||||
// -scroll_left
|
-scroll_left
|
||||||
// },
|
},
|
||||||
// end_x: if row == range_end.row() {
|
end_x: if row == range_end.row() {
|
||||||
// line_layout.x_for_index(range_end.column() as usize)
|
line_layout.x_for_index(range_end.column() as usize)
|
||||||
// - scroll_left
|
- scroll_left
|
||||||
// - descent
|
- descent
|
||||||
// } else {
|
} else {
|
||||||
// line_layout.width + corner_radius * 2.0 - scroll_left - descent
|
line_layout.width + corner_radius * 2.0 - scroll_left - descent
|
||||||
// },
|
},
|
||||||
// }
|
}
|
||||||
// })
|
})
|
||||||
// .collect(),
|
.collect(),
|
||||||
// };
|
};
|
||||||
|
|
||||||
// selection.paint(scene);
|
selection.paint(ctx.scene);
|
||||||
// }
|
}
|
||||||
|
|
||||||
if view.cursors_visible() {
|
if view.cursors_visible() {
|
||||||
let cursor_position = selection.end;
|
let cursor_position = selection.end;
|
||||||
@ -597,20 +598,47 @@ impl Selection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn paint_lines(&self, start_y: f32, lines: &[SelectionLine], scene: &mut Scene) {
|
fn paint_lines(&self, start_y: f32, lines: &[SelectionLine], scene: &mut Scene) {
|
||||||
// use Direction::*;
|
if lines.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// if lines.is_empty() {
|
let mut path = PathBuilder::new();
|
||||||
// return;
|
let corner_radius = 0.08 * self.line_height;
|
||||||
// }
|
|
||||||
|
|
||||||
// let mut path = Path2D::new();
|
let first_line = lines.first().unwrap();
|
||||||
// let corner_radius = 0.08 * self.line_height;
|
path.reset(vec2f(first_line.end_x - corner_radius, start_y));
|
||||||
|
path.curve_to(
|
||||||
|
vec2f(first_line.end_x, start_y + corner_radius),
|
||||||
|
vec2f(first_line.end_x, start_y),
|
||||||
|
);
|
||||||
|
path.line_to(vec2f(
|
||||||
|
first_line.end_x,
|
||||||
|
start_y + self.line_height - corner_radius,
|
||||||
|
));
|
||||||
|
path.curve_to(
|
||||||
|
vec2f(first_line.end_x - corner_radius, start_y + self.line_height),
|
||||||
|
vec2f(first_line.end_x, start_y + self.line_height),
|
||||||
|
);
|
||||||
|
path.line_to(vec2f(
|
||||||
|
first_line.start_x + corner_radius,
|
||||||
|
start_y + self.line_height,
|
||||||
|
));
|
||||||
|
path.curve_to(
|
||||||
|
vec2f(
|
||||||
|
first_line.start_x,
|
||||||
|
start_y + self.line_height - corner_radius,
|
||||||
|
),
|
||||||
|
vec2f(first_line.start_x, start_y + self.line_height),
|
||||||
|
);
|
||||||
|
path.line_to(vec2f(first_line.start_x, start_y + corner_radius));
|
||||||
|
path.curve_to(
|
||||||
|
vec2f(first_line.start_x + corner_radius, start_y),
|
||||||
|
vec2f(first_line.start_x, start_y),
|
||||||
|
);
|
||||||
|
path.line_to(vec2f(first_line.end_x - corner_radius, start_y));
|
||||||
|
|
||||||
// let first_line = lines.first().unwrap();
|
scene.push_path(ColorU::from_u32(0xff0000ff), path.build());
|
||||||
// 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);
|
// rounded_corner(&mut path, corner, corner_radius, Right, Down);
|
||||||
|
|
||||||
// let mut iter = lines.iter().enumerate().peekable();
|
// let mut iter = lines.iter().enumerate().peekable();
|
||||||
|
Loading…
Reference in New Issue
Block a user