Allow for undefined buffer width and/or height, fixes #70
This commit is contained in:
parent
cd1cd0a337
commit
93a7df859a
15 changed files with 99 additions and 72 deletions
|
|
@ -10,7 +10,7 @@ fn load_font_system(c: &mut Criterion) {
|
|||
fn layout(c: &mut Criterion) {
|
||||
let mut fs = ct::FontSystem::new();
|
||||
let mut buffer = ct::Buffer::new(&mut fs, ct::Metrics::new(10.0, 10.0));
|
||||
buffer.set_size(&mut fs, 80.0, f32::MAX);
|
||||
buffer.set_size(&mut fs, Some(80.0), None);
|
||||
|
||||
for (wrap_name, wrap) in &[
|
||||
("None", ct::Wrap::None),
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ fn main() {
|
|||
let mut buffer = Buffer::new(&mut font_system, font_sizes[font_size_default]);
|
||||
buffer
|
||||
.borrow_with(&mut font_system)
|
||||
.set_size(window.width() as f32, window.height() as f32);
|
||||
.set_size(Some(window.width() as f32), Some(window.height() as f32));
|
||||
|
||||
let mut editor = Editor::new(buffer);
|
||||
|
||||
|
|
|
|||
|
|
@ -110,8 +110,8 @@ fn main() {
|
|||
|
||||
editor.with_buffer_mut(|buffer| {
|
||||
buffer.set_size(
|
||||
width as f32 - scrollbar_width * display_scale,
|
||||
height as f32,
|
||||
Some(width as f32 - scrollbar_width * display_scale),
|
||||
Some(height as f32),
|
||||
)
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ fn main() {
|
|||
// Set scroll to view scroll
|
||||
buffer.set_scroll(*scroll);
|
||||
// Set size, will relayout and shape until scroll if changed
|
||||
buffer.set_size(width as f32, height as f32);
|
||||
buffer.set_size(Some(width as f32), Some(height as f32));
|
||||
// Shape until scroll, ensures scroll is clamped
|
||||
//TODO: ability to prune with multiple views?
|
||||
buffer.shape_until_scroll(true);
|
||||
|
|
@ -154,10 +154,10 @@ fn main() {
|
|||
scroll.vertical -= buffer.metrics().line_height;
|
||||
}
|
||||
Key::Named(NamedKey::PageDown) => {
|
||||
scroll.vertical += buffer.size().1;
|
||||
scroll.vertical += buffer.size().1.unwrap_or(0.0);
|
||||
}
|
||||
Key::Named(NamedKey::PageUp) => {
|
||||
scroll.vertical -= buffer.size().1;
|
||||
scroll.vertical -= buffer.size().1.unwrap_or(0.0);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -122,8 +122,8 @@ fn main() {
|
|||
let mut editor = editor.borrow_with(&mut font_system);
|
||||
editor.with_buffer_mut(|buffer| {
|
||||
buffer.set_size(
|
||||
window.inner_size().width as f32,
|
||||
window.inner_size().height as f32,
|
||||
Some(window.inner_size().width as f32),
|
||||
Some(window.inner_size().height as f32),
|
||||
)
|
||||
});
|
||||
editor.with_buffer_mut(|buffer| set_buffer_text(buffer));
|
||||
|
|
@ -182,7 +182,7 @@ fn main() {
|
|||
pixmap.fill(bg_color);
|
||||
|
||||
editor.with_buffer_mut(|buffer| {
|
||||
buffer.set_size(width as f32, height as f32)
|
||||
buffer.set_size(Some(width as f32), Some(height as f32))
|
||||
});
|
||||
|
||||
let mut paint = Paint::default();
|
||||
|
|
|
|||
|
|
@ -26,8 +26,8 @@ fn main() {
|
|||
|
||||
// Set a size for the text buffer, in pixels
|
||||
let width = 80.0;
|
||||
let height = f32::MAX; // The height is unbounded
|
||||
buffer.set_size(width, height);
|
||||
// The height is unbounded
|
||||
buffer.set_size(Some(width), None);
|
||||
|
||||
// Attributes indicate what font to choose
|
||||
let attrs = Attrs::new();
|
||||
|
|
@ -45,7 +45,6 @@ fn main() {
|
|||
const TEXT_COLOR: Color = Color::rgb(0xFF, 0xFF, 0xFF);
|
||||
|
||||
// Set up the canvas
|
||||
let width = buffer.size().0;
|
||||
let height = LINE_HEIGHT * buffer.layout_runs().count() as f32;
|
||||
let mut canvas = vec![vec![None; width as usize]; height as usize];
|
||||
|
||||
|
|
|
|||
108
src/buffer.rs
108
src/buffer.rs
|
|
@ -129,8 +129,10 @@ impl<'b> Iterator for LayoutRunIter<'b> {
|
|||
let glyph_height = layout_line.max_ascent + layout_line.max_descent;
|
||||
let centering_offset = (line_height - glyph_height) / 2.0;
|
||||
let line_y = line_top + centering_offset + layout_line.max_ascent;
|
||||
if line_top + centering_offset > self.buffer.height {
|
||||
return None;
|
||||
if let Some(height) = self.buffer.height_opt {
|
||||
if line_top + centering_offset > height {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
self.line_top += line_height;
|
||||
if line_y < 0.0 {
|
||||
|
|
@ -203,8 +205,8 @@ pub struct Buffer {
|
|||
/// [BufferLine]s (or paragraphs) of text in the buffer
|
||||
pub lines: Vec<BufferLine>,
|
||||
metrics: Metrics,
|
||||
width: f32,
|
||||
height: f32,
|
||||
width_opt: Option<f32>,
|
||||
height_opt: Option<f32>,
|
||||
scroll: Scroll,
|
||||
/// True if a redraw is requires. Set to false after processing
|
||||
redraw: bool,
|
||||
|
|
@ -221,8 +223,8 @@ impl Clone for Buffer {
|
|||
Self {
|
||||
lines: self.lines.clone(),
|
||||
metrics: self.metrics,
|
||||
width: self.width,
|
||||
height: self.height,
|
||||
width_opt: self.width_opt,
|
||||
height_opt: self.height_opt,
|
||||
scroll: self.scroll,
|
||||
redraw: self.redraw,
|
||||
wrap: self.wrap,
|
||||
|
|
@ -250,8 +252,8 @@ impl Buffer {
|
|||
Self {
|
||||
lines: Vec::new(),
|
||||
metrics,
|
||||
width: 0.0,
|
||||
height: 0.0,
|
||||
width_opt: None,
|
||||
height_opt: None,
|
||||
scroll: Scroll::default(),
|
||||
redraw: false,
|
||||
wrap: Wrap::WordOrGlyph,
|
||||
|
|
@ -294,7 +296,7 @@ impl Buffer {
|
|||
&mut self.scratch,
|
||||
font_system,
|
||||
self.metrics.font_size,
|
||||
Some(self.width),
|
||||
self.width_opt,
|
||||
self.wrap,
|
||||
self.monospace_width,
|
||||
self.tab_width,
|
||||
|
|
@ -315,7 +317,6 @@ impl Buffer {
|
|||
cursor: Cursor,
|
||||
prune: bool,
|
||||
) {
|
||||
let height = self.height;
|
||||
let metrics = self.metrics;
|
||||
let old_scroll = self.scroll;
|
||||
|
||||
|
|
@ -345,7 +346,7 @@ impl Buffer {
|
|||
// Adjust scroll backwards if cursor is before it
|
||||
self.scroll.line = layout_cursor.line;
|
||||
self.scroll.vertical = layout_y;
|
||||
} else {
|
||||
} else if let Some(height) = self.height_opt {
|
||||
// Adjust scroll forwards if cursor is after it
|
||||
let mut line_i = layout_cursor.line;
|
||||
while line_i > self.scroll.line {
|
||||
|
|
@ -389,9 +390,11 @@ impl Buffer {
|
|||
self.scroll.horizontal = x_min;
|
||||
self.redraw = true;
|
||||
}
|
||||
if x_max > self.scroll.horizontal + self.width {
|
||||
self.scroll.horizontal = x_max - self.width;
|
||||
self.redraw = true;
|
||||
if let Some(width) = self.width_opt {
|
||||
if x_max > self.scroll.horizontal + width {
|
||||
self.scroll.horizontal = x_max - width;
|
||||
self.redraw = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -424,7 +427,7 @@ impl Buffer {
|
|||
}
|
||||
|
||||
let scroll_start = self.scroll.vertical;
|
||||
let scroll_end = scroll_start + self.height;
|
||||
let scroll_end = scroll_start + self.height_opt.unwrap_or(f32::INFINITY);
|
||||
|
||||
let mut total_height = 0.0;
|
||||
for line_i in 0..self.lines.len() {
|
||||
|
|
@ -528,7 +531,7 @@ impl Buffer {
|
|||
&mut self.scratch,
|
||||
font_system,
|
||||
self.metrics.font_size,
|
||||
Some(self.width),
|
||||
self.width_opt,
|
||||
self.wrap,
|
||||
self.monospace_width,
|
||||
self.tab_width,
|
||||
|
|
@ -546,7 +549,7 @@ impl Buffer {
|
|||
///
|
||||
/// Will panic if `metrics.font_size` is zero.
|
||||
pub fn set_metrics(&mut self, font_system: &mut FontSystem, metrics: Metrics) {
|
||||
self.set_metrics_and_size(font_system, metrics, self.width, self.height);
|
||||
self.set_metrics_and_size(font_system, metrics, self.width_opt, self.height_opt);
|
||||
}
|
||||
|
||||
/// Get the current [`Wrap`]
|
||||
|
|
@ -608,13 +611,18 @@ impl Buffer {
|
|||
}
|
||||
|
||||
/// Get the current buffer dimensions (width, height)
|
||||
pub fn size(&self) -> (f32, f32) {
|
||||
(self.width, self.height)
|
||||
pub fn size(&self) -> (Option<f32>, Option<f32>) {
|
||||
(self.width_opt, self.height_opt)
|
||||
}
|
||||
|
||||
/// Set the current buffer dimensions
|
||||
pub fn set_size(&mut self, font_system: &mut FontSystem, width: f32, height: f32) {
|
||||
self.set_metrics_and_size(font_system, self.metrics, width, height);
|
||||
pub fn set_size(
|
||||
&mut self,
|
||||
font_system: &mut FontSystem,
|
||||
width_opt: Option<f32>,
|
||||
height_opt: Option<f32>,
|
||||
) {
|
||||
self.set_metrics_and_size(font_system, self.metrics, width_opt, height_opt);
|
||||
}
|
||||
|
||||
/// Set the current [`Metrics`] and buffer dimensions at the same time
|
||||
|
|
@ -626,17 +634,20 @@ impl Buffer {
|
|||
&mut self,
|
||||
font_system: &mut FontSystem,
|
||||
metrics: Metrics,
|
||||
width: f32,
|
||||
height: f32,
|
||||
width_opt: Option<f32>,
|
||||
height_opt: Option<f32>,
|
||||
) {
|
||||
let clamped_width = width.max(0.0);
|
||||
let clamped_height = height.max(0.0);
|
||||
let clamped_width_opt = width_opt.map(|width| width.max(0.0));
|
||||
let clamped_height_opt = height_opt.map(|height| height.max(0.0));
|
||||
|
||||
if metrics != self.metrics || clamped_width != self.width || clamped_height != self.height {
|
||||
if metrics != self.metrics
|
||||
|| clamped_width_opt != self.width_opt
|
||||
|| clamped_height_opt != self.height_opt
|
||||
{
|
||||
assert_ne!(metrics.font_size, 0.0, "font size cannot be 0");
|
||||
self.metrics = metrics;
|
||||
self.width = clamped_width;
|
||||
self.height = clamped_height;
|
||||
self.width_opt = clamped_width_opt;
|
||||
self.height_opt = clamped_height_opt;
|
||||
self.relayout(font_system);
|
||||
self.shape_until_scroll(font_system, false);
|
||||
}
|
||||
|
|
@ -1128,20 +1139,24 @@ impl Buffer {
|
|||
cursor_x_opt = None;
|
||||
}
|
||||
Motion::PageUp => {
|
||||
(cursor, cursor_x_opt) = self.cursor_motion(
|
||||
font_system,
|
||||
cursor,
|
||||
cursor_x_opt,
|
||||
Motion::Vertical(-self.size().1 as i32),
|
||||
)?;
|
||||
if let Some(height) = self.height_opt {
|
||||
(cursor, cursor_x_opt) = self.cursor_motion(
|
||||
font_system,
|
||||
cursor,
|
||||
cursor_x_opt,
|
||||
Motion::Vertical(-height as i32),
|
||||
)?;
|
||||
}
|
||||
}
|
||||
Motion::PageDown => {
|
||||
(cursor, cursor_x_opt) = self.cursor_motion(
|
||||
font_system,
|
||||
cursor,
|
||||
cursor_x_opt,
|
||||
Motion::Vertical(self.size().1 as i32),
|
||||
)?;
|
||||
if let Some(height) = self.height_opt {
|
||||
(cursor, cursor_x_opt) = self.cursor_motion(
|
||||
font_system,
|
||||
cursor,
|
||||
cursor_x_opt,
|
||||
Motion::Vertical(height as i32),
|
||||
)?;
|
||||
}
|
||||
}
|
||||
Motion::Vertical(px) => {
|
||||
// TODO more efficient, use layout run line height
|
||||
|
|
@ -1341,8 +1356,8 @@ impl<'a> BorrowedWithFontSystem<'a, Buffer> {
|
|||
}
|
||||
|
||||
/// Set the current buffer dimensions
|
||||
pub fn set_size(&mut self, width: f32, height: f32) {
|
||||
self.inner.set_size(self.font_system, width, height);
|
||||
pub fn set_size(&mut self, width_opt: Option<f32>, height_opt: Option<f32>) {
|
||||
self.inner.set_size(self.font_system, width_opt, height_opt);
|
||||
}
|
||||
|
||||
/// Set the current [`Metrics`] and buffer dimensions at the same time
|
||||
|
|
@ -1350,9 +1365,14 @@ impl<'a> BorrowedWithFontSystem<'a, Buffer> {
|
|||
/// # Panics
|
||||
///
|
||||
/// Will panic if `metrics.font_size` is zero.
|
||||
pub fn set_metrics_and_size(&mut self, metrics: Metrics, width: f32, height: f32) {
|
||||
pub fn set_metrics_and_size(
|
||||
&mut self,
|
||||
metrics: Metrics,
|
||||
width_opt: Option<f32>,
|
||||
height_opt: Option<f32>,
|
||||
) {
|
||||
self.inner
|
||||
.set_metrics_and_size(self.font_system, metrics, width, height);
|
||||
.set_metrics_and_size(self.font_system, metrics, width_opt, height_opt);
|
||||
}
|
||||
|
||||
/// Set text of buffer, using provided attributes for each line by default
|
||||
|
|
|
|||
|
|
@ -167,7 +167,7 @@ impl<'buffer> Editor<'buffer> {
|
|||
|
||||
if run.glyphs.is_empty() && end.line > line_i {
|
||||
// Highlight all of internal empty lines
|
||||
range_opt = Some((0, buffer.size().0 as i32));
|
||||
range_opt = Some((0, buffer.size().0.unwrap_or(0.0) as i32));
|
||||
}
|
||||
|
||||
if let Some((mut min, mut max)) = range_opt.take() {
|
||||
|
|
@ -176,7 +176,7 @@ impl<'buffer> Editor<'buffer> {
|
|||
if run.rtl {
|
||||
min = 0;
|
||||
} else {
|
||||
max = buffer.size().0 as i32;
|
||||
max = buffer.size().0.unwrap_or(0.0) as i32;
|
||||
}
|
||||
}
|
||||
f(
|
||||
|
|
|
|||
|
|
@ -201,7 +201,11 @@ impl<'syntax_system, 'buffer> SyntaxEditor<'syntax_system, 'buffer> {
|
|||
F: FnMut(i32, i32, u32, u32, Color),
|
||||
{
|
||||
let size = self.with_buffer(|buffer| buffer.size());
|
||||
f(0, 0, size.0 as u32, size.1 as u32, self.background_color());
|
||||
if let Some(width) = size.0 {
|
||||
if let Some(height) = size.1 {
|
||||
f(0, 0, width as u32, height as u32, self.background_color());
|
||||
}
|
||||
}
|
||||
self.editor.draw(
|
||||
font_system,
|
||||
cache,
|
||||
|
|
@ -263,7 +267,7 @@ impl<'syntax_system, 'buffer> Edit<'buffer> for SyntaxEditor<'syntax_system, 'bu
|
|||
self.editor.with_buffer_mut(|buffer| {
|
||||
let metrics = buffer.metrics();
|
||||
let scroll = buffer.scroll();
|
||||
let scroll_end = scroll.vertical + buffer.size().1;
|
||||
let scroll_end = scroll.vertical + buffer.size().1.unwrap_or(f32::INFINITY);
|
||||
let mut total_height = 0.0;
|
||||
let mut highlighted = 0;
|
||||
for line_i in 0..buffer.lines.len() {
|
||||
|
|
|
|||
|
|
@ -310,7 +310,11 @@ impl<'syntax_system, 'buffer> ViEditor<'syntax_system, 'buffer> {
|
|||
let selection_color = self.selection_color();
|
||||
self.with_buffer(|buffer| {
|
||||
let size = buffer.size();
|
||||
f(0, 0, size.0 as u32, size.1 as u32, background_color);
|
||||
if let Some(width) = size.0 {
|
||||
if let Some(height) = size.1 {
|
||||
f(0, 0, width as u32, height as u32, background_color);
|
||||
}
|
||||
}
|
||||
let font_size = buffer.metrics().font_size;
|
||||
for run in buffer.layout_runs() {
|
||||
let line_i = run.line_i;
|
||||
|
|
@ -393,7 +397,7 @@ impl<'syntax_system, 'buffer> ViEditor<'syntax_system, 'buffer> {
|
|||
|
||||
if run.glyphs.is_empty() && end.line > line_i {
|
||||
// Highlight all of internal empty lines
|
||||
range_opt = Some((0, buffer.size().0 as i32));
|
||||
range_opt = Some((0, buffer.size().0.unwrap_or(0.0) as i32));
|
||||
}
|
||||
|
||||
if let Some((mut min, mut max)) = range_opt.take() {
|
||||
|
|
@ -402,7 +406,7 @@ impl<'syntax_system, 'buffer> ViEditor<'syntax_system, 'buffer> {
|
|||
if run.rtl {
|
||||
min = 0;
|
||||
} else {
|
||||
max = buffer.size().0 as i32;
|
||||
max = buffer.size().0.unwrap_or(0.0) as i32;
|
||||
}
|
||||
}
|
||||
f(
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@
|
|||
//! let mut buffer = buffer.borrow_with(&mut font_system);
|
||||
//!
|
||||
//! // Set a size for the text buffer, in pixels
|
||||
//! buffer.set_size(80.0, 25.0);
|
||||
//! buffer.set_size(Some(80.0), Some(25.0));
|
||||
//!
|
||||
//! // Attributes indicate what font to choose
|
||||
//! let attrs = Attrs::new();
|
||||
|
|
|
|||
|
|
@ -852,7 +852,7 @@ impl ShapeLine {
|
|||
for span in spans.iter_mut() {
|
||||
for word in span.words.iter_mut() {
|
||||
for glyph in word.glyphs.iter_mut() {
|
||||
if &line[glyph.start..glyph.end] == "\t" {
|
||||
if line.get(glyph.start..glyph.end) == Some("\t") {
|
||||
//TODO: better fallback for width
|
||||
let space_x_advance =
|
||||
glyph.font_monospace_em_width.unwrap_or(glyph.x_advance);
|
||||
|
|
|
|||
|
|
@ -89,8 +89,8 @@ impl DrawTestCfg {
|
|||
let mut buffer = buffer.borrow_with(&mut font_system);
|
||||
let margins = 5;
|
||||
buffer.set_size(
|
||||
(self.canvas_width - margins * 2) as f32,
|
||||
(self.canvas_height - margins * 2) as f32,
|
||||
Some((self.canvas_width - margins * 2) as f32),
|
||||
Some((self.canvas_height - margins * 2) as f32),
|
||||
);
|
||||
buffer.set_text(&self.text, self.font.as_attrs(), Shaping::Advanced);
|
||||
buffer.shape_until_scroll(true);
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ fn wrap_extra_line() {
|
|||
buffer.set_text("Lorem ipsum dolor sit amet, qui minim labore adipisicing\n\nweeewoooo minim sint cillum sint consectetur cupidatat.", Attrs::new().family(cosmic_text::Family::Name("Inter")), Shaping::Advanced);
|
||||
|
||||
// Set a size for the text buffer, in pixels
|
||||
buffer.set_size(50.0, 1000.0);
|
||||
buffer.set_size(Some(50.0), Some(1000.0));
|
||||
|
||||
// Perform shaping as desired
|
||||
buffer.shape_until_scroll(false);
|
||||
|
|
|
|||
|
|
@ -16,17 +16,17 @@ fn wrap_word_fallback() {
|
|||
|
||||
buffer.set_wrap(Wrap::WordOrGlyph);
|
||||
buffer.set_text("Lorem ipsum dolor sit amet, qui minim labore adipisicing minim sint cillum sint consectetur cupidatat.", Attrs::new().family(cosmic_text::Family::Name("Inter")), Shaping::Advanced);
|
||||
buffer.set_size(50.0, 1000.0);
|
||||
buffer.set_size(Some(50.0), Some(1000.0));
|
||||
|
||||
buffer.shape_until_scroll(false);
|
||||
|
||||
let measured_size = measure(&buffer);
|
||||
|
||||
assert!(
|
||||
measured_size <= buffer.size().0,
|
||||
measured_size <= buffer.size().0.unwrap_or(0.0),
|
||||
"Measured width is larger than buffer width\n{} <= {}",
|
||||
measured_size,
|
||||
buffer.size().0
|
||||
buffer.size().0.unwrap_or(0.0)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue