From 4320ae6329758e1ab49fdb5c41f0a5be3f5b14a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ram=C3=B3n=20Jim=C3=A9nez?= Date: Sat, 4 Feb 2023 11:13:53 +0100 Subject: [PATCH] Use `f32` instead of `i32` for lengths This allows users to use logical coordinates instead of physical ones. --- examples/editor-libcosmic/src/main.rs | 74 ++++++++++++++++++----- examples/editor-libcosmic/src/text.rs | 18 +++--- examples/editor-libcosmic/src/text_box.rs | 8 +-- examples/editor-orbclient/src/main.rs | 36 ++++++----- examples/editor-test/src/main.rs | 16 ++--- examples/rich-text/src/main.rs | 10 +-- examples/terminal/src/main.rs | 6 +- src/buffer.rs | 58 +++++++++--------- src/buffer_line.rs | 4 +- src/cache.rs | 8 +-- src/edit/editor.rs | 22 +++---- src/edit/vi.rs | 22 ++++--- src/lib.rs | 4 +- src/shape.rs | 68 ++++++++++----------- src/swash.rs | 4 +- 15 files changed, 203 insertions(+), 155 deletions(-) diff --git a/examples/editor-libcosmic/src/main.rs b/examples/editor-libcosmic/src/main.rs index 974e97f..911e1ab 100644 --- a/examples/editor-libcosmic/src/main.rs +++ b/examples/editor-libcosmic/src/main.rs @@ -14,7 +14,7 @@ use cosmic::{ use cosmic_text::{ Align, Attrs, AttrsList, Buffer, Edit, FontSystem, Metrics, SyntaxEditor, SyntaxSystem, Wrap, }; -use std::{env, fs, path::PathBuf, sync::Mutex}; +use std::{env, fmt, fs, path::PathBuf, sync::Mutex}; use self::text::text; mod text; @@ -27,14 +27,52 @@ lazy_static::lazy_static! { static ref SYNTAX_SYSTEM: SyntaxSystem = SyntaxSystem::new(); } -static FONT_SIZES: &'static [Metrics] = &[ - Metrics::new(10, 14), // Caption - Metrics::new(14, 20), // Body - Metrics::new(20, 28), // Title 4 - Metrics::new(24, 32), // Title 3 - Metrics::new(28, 36), // Title 2 - Metrics::new(32, 44), // Title 1 -]; +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum FontSize { + Caption, + Body, + Title4, + Title3, + Title2, + Title1, +} + +impl FontSize { + pub fn all() -> &'static [Self] { + &[ + Self::Caption, + Self::Body, + Self::Title4, + Self::Title3, + Self::Title2, + Self::Title1, + ] + } + + pub fn to_metrics(self) -> Metrics { + match self { + Self::Caption => Metrics::new(10.0, 14.0), // Caption + Self::Body => Metrics::new(14.0, 20.0), // Body + Self::Title4 => Metrics::new(20.0, 28.0), // Title 4 + Self::Title3 => Metrics::new(24.0, 32.0), // Title 3 + Self::Title2 => Metrics::new(28.0, 36.0), // Title 2 + Self::Title1 => Metrics::new(32.0, 44.0), // Title 1 + } + } +} + +impl fmt::Display for FontSize { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::Caption => write!(f, "Caption"), + Self::Body => write!(f, "Body"), + Self::Title4 => write!(f, "Title 4"), + Self::Title3 => write!(f, "Title 3"), + Self::Title2 => write!(f, "Title 2"), + Self::Title1 => write!(f, "Title 1"), + } + } +} static WRAP_MODE: &'static [Wrap] = &[Wrap::None, Wrap::Glyph, Wrap::Word]; @@ -50,6 +88,7 @@ pub struct Window { theme: Theme, path_opt: Option, attrs: Attrs<'static>, + font_size: FontSize, #[cfg(not(feature = "vi"))] editor: Mutex>, #[cfg(feature = "vi")] @@ -64,7 +103,7 @@ pub enum Message { Bold(bool), Italic(bool), Monospaced(bool), - MetricsChanged(Metrics), + FontSizeChanged(FontSize), WrapChanged(Wrap), AlignmentChanged(Align), ThemeChanged(&'static str), @@ -98,7 +137,7 @@ impl Application for Window { .family(cosmic_text::Family::Monospace); let mut editor = SyntaxEditor::new( - Buffer::new(&FONT_SYSTEM, FONT_SIZES[1 /* Body */]), + Buffer::new(&FONT_SYSTEM, FontSize::Body.to_metrics()), &SYNTAX_SYSTEM, "base16-eighties.dark", ) @@ -111,6 +150,7 @@ impl Application for Window { let mut window = Window { theme: Theme::Dark, + font_size: FontSize::Body, path_opt: None, attrs, editor: Mutex::new(editor), @@ -195,9 +235,11 @@ impl Application for Window { let mut editor = self.editor.lock().unwrap(); update_attrs(&mut *editor, self.attrs); } - Message::MetricsChanged(metrics) => { + Message::FontSizeChanged(font_size) => { + self.font_size = font_size; + let mut editor = self.editor.lock().unwrap(); - editor.buffer_mut().set_metrics(metrics); + editor.buffer_mut().set_metrics(font_size.to_metrics()); } Message::WrapChanged(wrap) => { let mut editor = self.editor.lock().unwrap(); @@ -245,9 +287,9 @@ impl Application for Window { let font_size_picker = { let editor = self.editor.lock().unwrap(); pick_list( - FONT_SIZES, - Some(editor.buffer().metrics()), - Message::MetricsChanged, + FontSize::all(), + Some(self.font_size), + Message::FontSizeChanged, ) }; diff --git a/examples/editor-libcosmic/src/text.rs b/examples/editor-libcosmic/src/text.rs index 4b487d8..0392842 100644 --- a/examples/editor-libcosmic/src/text.rs +++ b/examples/editor-libcosmic/src/text.rs @@ -55,7 +55,7 @@ impl Text { let text = Self { line, - metrics: Metrics::new(14, 20), + metrics: Metrics::new(14.0, 20.0), }; log::debug!("Text::new in {:?}", instant.elapsed()); @@ -99,17 +99,17 @@ where //TODO: can we cache this? let layout_lines = shape.layout( self.metrics.font_size, - limits.max().width as i32, + limits.max().width, self.line.wrap(), self.line.align(), ); - let mut width = 0; - let mut height = 0; + let mut width = 0.0f32; + let mut height = 0.0f32; for layout_line in layout_lines { for glyph in layout_line.glyphs.iter() { - width = cmp::max(width, (glyph.x + glyph.w) as i32 + 1); + width = width.max((glyph.x + glyph.w) + 1.0); } height += self.metrics.line_height; } @@ -156,8 +156,8 @@ where cmp::max(0, cmp::min(255, (appearance.text_color.a * 255.0) as i32)) as u8, ); - let layout_w = layout.bounds().width as i32; - let layout_h = layout.bounds().height as i32; + let layout_w = layout.bounds().width; + let layout_h = layout.bounds().height; let shape = self.line.shape_opt().as_ref().unwrap(); @@ -185,8 +185,8 @@ where cache.with_pixels(cache_key, glyph_color, |pixel_x, pixel_y, color| { let x = x_int + pixel_x; - let y = line_y + y_int + pixel_y; - draw_pixel(&mut pixels, layout_w, layout_h, x, y, color); + let y = line_y as i32 + y_int + pixel_y; + draw_pixel(&mut pixels, layout_w as i32, layout_h as i32, x, y, color); }); } line_y += self.metrics.line_height; diff --git a/examples/editor-libcosmic/src/text_box.rs b/examples/editor-libcosmic/src/text_box.rs index 8a6b6fc..d10081e 100644 --- a/examples/editor-libcosmic/src/text_box.rs +++ b/examples/editor-libcosmic/src/text_box.rs @@ -160,10 +160,8 @@ where let mut editor = self.editor.lock().unwrap(); - let view_w = cmp::min(viewport.width as i32, layout.bounds().width as i32) - - self.padding.horizontal() as i32; - let view_h = cmp::min(viewport.height as i32, layout.bounds().height as i32) - - self.padding.vertical() as i32; + let view_w = viewport.width.min(layout.bounds().width) - self.padding.horizontal() as f32; + let view_h = viewport.height.min(layout.bounds().height) - self.padding.vertical() as f32; editor.buffer_mut().set_size(view_w, view_h); editor.shape_as_needed(); @@ -203,7 +201,7 @@ where ), ); } else { - text::draw_pixel(&mut pixels, view_w, view_h, x, y, color); + text::draw_pixel(&mut pixels, view_w as i32, view_h as i32, x, y, color); } }, ); diff --git a/examples/editor-orbclient/src/main.rs b/examples/editor-orbclient/src/main.rs index 075c7c2..d203d97 100644 --- a/examples/editor-orbclient/src/main.rs +++ b/examples/editor-orbclient/src/main.rs @@ -22,11 +22,11 @@ fn main() { let display_scale = match orbclient::get_display_size() { Ok((w, h)) => { log::info!("Display size: {}, {}", w, h); - (h as i32 / 1600) + 1 + (h as f32 / 1600.0) + 1.0 } Err(err) => { log::warn!("Failed to get display size: {}", err); - 1 + 1.0 } }; @@ -45,17 +45,17 @@ fn main() { let syntax_system = SyntaxSystem::new(); let font_sizes = [ - Metrics::new(10, 14).scale(display_scale), // Caption - Metrics::new(14, 20).scale(display_scale), // Body - Metrics::new(20, 28).scale(display_scale), // Title 4 - Metrics::new(24, 32).scale(display_scale), // Title 3 - Metrics::new(28, 36).scale(display_scale), // Title 2 - Metrics::new(32, 44).scale(display_scale), // Title 1 + Metrics::new(10.0, 14.0).scale(display_scale), // Caption + Metrics::new(14.0, 20.0).scale(display_scale), // Body + Metrics::new(20.0, 28.0).scale(display_scale), // Title 4 + Metrics::new(24.0, 32.0).scale(display_scale), // Title 3 + Metrics::new(28.0, 36.0).scale(display_scale), // Title 2 + Metrics::new(32.0, 44.0).scale(display_scale), // Title 1 ]; let font_size_default = 1; // Body let mut font_size_i = font_size_default; - let line_x = 8 * display_scale; + let line_x = 8.0 * display_scale; let mut editor = SyntaxEditor::new( Buffer::new(&font_system, font_sizes[font_size_i]), @@ -69,7 +69,7 @@ fn main() { editor .buffer_mut() - .set_size(window.width() as i32 - line_x * 2, window.height() as i32); + .set_size(window.width() as f32 - line_x * 2.0, window.height() as f32); let attrs = Attrs::new().monospaced(true).family(Family::Monospace); match editor.load_text(&path, attrs) { @@ -95,7 +95,13 @@ fn main() { let fg = editor.foreground_color(); editor.draw(&mut swash_cache, fg, |x, y, w, h, color| { - window.rect(line_x + x, y, w, h, orbclient::Color { data: color.0 }) + window.rect( + line_x as i32 + x, + y, + w, + h, + orbclient::Color { data: color.0 }, + ) }); // Draw scrollbar @@ -177,7 +183,7 @@ fn main() { mouse_y = event.y; if mouse_left { editor.action(Action::Drag { - x: mouse_x - line_x, + x: mouse_x - line_x as i32, y: mouse_y, }); @@ -197,7 +203,7 @@ fn main() { mouse_left = event.left; if mouse_left { editor.action(Action::Click { - x: mouse_x - line_x, + x: mouse_x - line_x as i32, y: mouse_y, }); } @@ -207,7 +213,7 @@ fn main() { EventOption::Resize(event) => { editor .buffer_mut() - .set_size(event.width as i32 - line_x * 2, event.height as i32); + .set_size(event.width as f32 - line_x * 2.0, event.height as f32); } EventOption::Scroll(event) => { editor.action(Action::Scroll { @@ -221,7 +227,7 @@ fn main() { if mouse_left && force_drag { editor.action(Action::Drag { - x: mouse_x - line_x, + x: mouse_x - line_x as i32, y: mouse_y, }); diff --git a/examples/editor-test/src/main.rs b/examples/editor-test/src/main.rs index 5f70bec..53459d4 100644 --- a/examples/editor-test/src/main.rs +++ b/examples/editor-test/src/main.rs @@ -31,7 +31,7 @@ fn redraw(window: &mut Window, editor: &mut Editor<'_>, swash_cache: &mut SwashC fn main() { env_logger::init(); - let display_scale = 1; + let display_scale = 1.0; let font_system = FontSystem::new(); let mut window = Window::new_flags( @@ -45,17 +45,17 @@ fn main() { .unwrap(); let font_sizes = [ - Metrics::new(10, 14).scale(display_scale), // Caption - Metrics::new(14, 20).scale(display_scale), // Body - Metrics::new(20, 28).scale(display_scale), // Title 4 - Metrics::new(24, 32).scale(display_scale), // Title 3 - Metrics::new(28, 36).scale(display_scale), // Title 2 - Metrics::new(32, 44).scale(display_scale), // Title 1 + Metrics::new(10.0, 14.0).scale(display_scale), // Caption + Metrics::new(14.0, 20.0).scale(display_scale), // Body + Metrics::new(20.0, 28.0).scale(display_scale), // Title 4 + Metrics::new(24.0, 32.0).scale(display_scale), // Title 3 + Metrics::new(28.0, 36.0).scale(display_scale), // Title 2 + Metrics::new(32.0, 44.0).scale(display_scale), // Title 1 ]; let font_size_default = 1; // Body let mut buffer = Buffer::new(&font_system, font_sizes[font_size_default]); - buffer.set_size(window.width() as i32, window.height() as i32); + buffer.set_size(window.width() as f32, window.height() as f32); let mut editor = Editor::new(buffer); diff --git a/examples/rich-text/src/main.rs b/examples/rich-text/src/main.rs index 1595f6c..bfafaeb 100644 --- a/examples/rich-text/src/main.rs +++ b/examples/rich-text/src/main.rs @@ -18,11 +18,11 @@ fn main() { let display_scale = match orbclient::get_display_size() { Ok((w, h)) => { log::info!("Display size: {}, {}", w, h); - (h as i32 / 1600) + 1 + (h as f32 / 1600.0) + 1.0 } Err(err) => { log::warn!("Failed to get display size: {}", err); - 1 + 1.0 } }; @@ -38,12 +38,12 @@ fn main() { let mut editor = Editor::new(Buffer::new( &font_system, - Metrics::new(32, 44).scale(display_scale), + Metrics::new(32.0, 44.0).scale(display_scale), )); editor .buffer_mut() - .set_size(window.width() as i32, window.height() as i32); + .set_size(window.width() as f32, window.height() as f32); let attrs = Attrs::new(); let serif_attrs = attrs.family(Family::Serif); @@ -211,7 +211,7 @@ fn main() { EventOption::Resize(resize) => { editor .buffer_mut() - .set_size(resize.width as i32, resize.height as i32); + .set_size(resize.width as f32, resize.height as f32); } EventOption::Quit(_) => process::exit(0), _ => (), diff --git a/examples/terminal/src/main.rs b/examples/terminal/src/main.rs index fb16071..bf6a610 100644 --- a/examples/terminal/src/main.rs +++ b/examples/terminal/src/main.rs @@ -12,7 +12,7 @@ fn main() { let mut swash_cache = SwashCache::new(&font_system); // Text metrics indicate the font size and line height of a buffer - let metrics = Metrics::new(14, 20); + let metrics = Metrics::new(14.0, 20.0); // A Buffer provides shaping and layout for a UTF-8 string, create one per text widget let mut buffer = Buffer::new(&font_system, metrics); @@ -20,7 +20,7 @@ fn main() { // Set a size for the text buffer, in pixels let width = 80u16; let height = 25u16; - buffer.set_size(width as i32, height as i32); + buffer.set_size(width as f32, height as f32); // Attributes indicate what font to choose let attrs = Attrs::new(); @@ -39,7 +39,7 @@ fn main() { // Clear buffer with black background for _y in 0..height { - for _x in 0..buffer.size().0 { + for _x in 0..(buffer.size().0 as i32) { print!( "{} {}", color::Bg(color::Rgb(0, 0, 0)), diff --git a/src/buffer.rs b/src/buffer.rs index 2f7f920..37066c3 100644 --- a/src/buffer.rs +++ b/src/buffer.rs @@ -107,7 +107,7 @@ pub struct LayoutRun<'a> { /// The array of layout glyphs to draw pub glyphs: &'a [LayoutGlyph], /// Y offset of line - pub line_y: i32, + pub line_y: f32, /// width of line pub line_w: f32, } @@ -174,7 +174,7 @@ pub struct LayoutRunIter<'a, 'b> { line_i: usize, layout_i: usize, remaining_len: usize, - line_y: i32, + line_y: f32, total_layout: i32, } @@ -192,16 +192,14 @@ impl<'a, 'b> LayoutRunIter<'a, 'b> { .sum(); let top_cropped_layout_lines = total_layout_lines.saturating_sub(buffer.scroll.try_into().unwrap_or_default()); - let maximum_lines = buffer - .height - .checked_div(buffer.metrics.line_height) - .unwrap_or_default(); + let maximum_lines = (buffer.height / buffer.metrics.line_height) as i32; let bottom_cropped_layout_lines = if top_cropped_layout_lines > maximum_lines.try_into().unwrap_or_default() { maximum_lines.try_into().unwrap_or_default() } else { top_cropped_layout_lines }; + Self { buffer, line_i: 0, @@ -259,30 +257,30 @@ impl<'a, 'b> Iterator for LayoutRunIter<'a, 'b> { impl<'a, 'b> ExactSizeIterator for LayoutRunIter<'a, 'b> {} /// Metrics of text -#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Default, PartialEq)] pub struct Metrics { /// Font size in pixels - pub font_size: i32, + pub font_size: f32, /// Line height in pixels - pub line_height: i32, + pub line_height: f32, } impl Metrics { - pub const fn new(font_size: i32, line_height: i32) -> Self { + pub const fn new(font_size: f32, line_height: f32) -> Self { Self { font_size, line_height, } } - pub const fn scale(self, scale: i32) -> Self { + pub fn scale(self, scale: f32) -> Self { Self { font_size: self.font_size * scale, line_height: self.line_height * scale, } } - fn y_offset(&self) -> i32 { + fn y_offset(&self) -> f32 { self.font_size - self.line_height } } @@ -299,8 +297,8 @@ pub struct Buffer<'a> { /// [BufferLine]s (or paragraphs) of text in the buffer pub lines: Vec, metrics: Metrics, - width: i32, - height: i32, + width: f32, + height: f32, scroll: i32, /// True if a redraw is requires. Set to false after processing redraw: bool, @@ -310,14 +308,14 @@ pub struct Buffer<'a> { impl<'a> Buffer<'a> { /// Create a new [`Buffer`] with the provided [`FontSystem`] and [`Metrics`] pub fn new(font_system: &'a FontSystem, metrics: Metrics) -> Self { - assert_ne!(metrics.line_height, 0, "line height cannot be 0"); + assert_ne!(metrics.line_height, 0.0, "line height cannot be 0"); let mut buffer = Self { font_system, lines: Vec::new(), metrics, - width: 0, - height: 0, + width: 0.0, + height: 0.0, scroll: 0, redraw: false, wrap: Wrap::Word, @@ -497,7 +495,7 @@ impl<'a> Buffer<'a> { /// Set the current [`Metrics`] pub fn set_metrics(&mut self, metrics: Metrics) { if metrics != self.metrics { - assert_ne!(metrics.font_size, 0, "font size cannot be 0"); + assert_ne!(metrics.font_size, 0.0, "font size cannot be 0"); self.metrics = metrics; self.relayout(); self.shape_until_scroll(); @@ -519,14 +517,14 @@ impl<'a> Buffer<'a> { } /// Get the current buffer dimensions (width, height) - pub fn size(&self) -> (i32, i32) { + pub fn size(&self) -> (f32, f32) { (self.width, self.height) } /// Set the current buffer dimensions - pub fn set_size(&mut self, width: i32, height: i32) { - let clamped_width = width.max(0); - let clamped_height = height.max(0); + pub fn set_size(&mut self, width: f32, height: f32) { + let clamped_width = width.max(0.0); + let clamped_height = height.max(0.0); if clamped_width != self.width || clamped_height != self.height { self.width = clamped_width; @@ -551,7 +549,7 @@ impl<'a> Buffer<'a> { /// Get the number of lines that can be viewed in the buffer pub fn visible_lines(&self) -> i32 { - self.height / self.metrics.line_height + (self.height / self.metrics.line_height) as i32 } /// Set text of buffer, using provided attributes for each line by default @@ -588,7 +586,7 @@ impl<'a> Buffer<'a> { } /// Convert x, y position to Cursor (hit detection) - pub fn hit(&self, x: i32, y: i32) -> Option { + pub fn hit(&self, x: f32, y: f32) -> Option { #[cfg(all(feature = "std", not(target_arch = "wasm32")))] let instant = std::time::Instant::now(); @@ -616,12 +614,12 @@ impl<'a> Buffer<'a> { 'hit: for (glyph_i, glyph) in run.glyphs.iter().enumerate() { if first_glyph { first_glyph = false; - if (run.rtl && x > glyph.x as i32) || (!run.rtl && x < 0) { + if (run.rtl && x > glyph.x) || (!run.rtl && x < 0.0) { new_cursor_glyph = 0; new_cursor_char = 0; } } - if x >= glyph.x as i32 && x <= (glyph.x + glyph.w) as i32 { + if x >= glyph.x && x <= glyph.x + glyph.w { new_cursor_glyph = glyph_i; let cluster = &run.text[glyph.start..glyph.end]; @@ -629,10 +627,10 @@ impl<'a> Buffer<'a> { let mut egc_x = glyph.x; let egc_w = glyph.w / (total as f32); for (egc_i, egc) in cluster.grapheme_indices(true) { - if x >= egc_x as i32 && x <= (egc_x + egc_w) as i32 { + if x >= egc_x && x <= egc_x + egc_w { new_cursor_char = egc_i; - let right_half = x >= (egc_x + egc_w / 2.0) as i32; + let right_half = x >= egc_x + egc_w / 2.0; if right_half != glyph.level.is_rtl() { // If clicking on last half of glyph, move cursor past glyph new_cursor_char += egc.len(); @@ -643,7 +641,7 @@ impl<'a> Buffer<'a> { egc_x += egc_w; } - let right_half = x >= (glyph.x + glyph.w / 2.0) as i32; + let right_half = x >= glyph.x + glyph.w / 2.0; if right_half != glyph.level.is_rtl() { // If clicking on last half of glyph, move cursor past glyph new_cursor_char = cluster.len(); @@ -704,7 +702,7 @@ impl<'a> Buffer<'a> { }; cache.with_pixels(cache_key, glyph_color, |x, y, color| { - f(x_int + x, run.line_y + y_int + y, 1, 1, color); + f(x_int + x, run.line_y as i32 + y_int + y, 1, 1, color); }); } } diff --git a/src/buffer_line.rs b/src/buffer_line.rs index c1f5b92..e9b7e0b 100644 --- a/src/buffer_line.rs +++ b/src/buffer_line.rs @@ -184,8 +184,8 @@ impl BufferLine { pub fn layout( &mut self, font_system: &FontSystem, - font_size: i32, - width: i32, + font_size: f32, + width: f32, wrap: Wrap, ) -> &[LayoutLine] { if self.layout_opt.is_none() { diff --git a/src/cache.rs b/src/cache.rs index 4859e3e..ce93b38 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -7,8 +7,8 @@ pub struct CacheKey { pub font_id: fontdb::ID, /// Glyph ID pub glyph_id: u16, - /// Font size in pixels - pub font_size: i32, + /// `f32` bits of font size + pub font_size_bits: u32, /// Binning of fractional X offset pub x_bin: SubpixelBin, /// Binning of fractional Y offset @@ -19,7 +19,7 @@ impl CacheKey { pub fn new( font_id: fontdb::ID, glyph_id: u16, - font_size: i32, + font_size: f32, pos: (f32, f32), ) -> (Self, i32, i32) { let (x, x_bin) = SubpixelBin::new(pos.0); @@ -28,7 +28,7 @@ impl CacheKey { Self { font_id, glyph_id, - font_size, + font_size_bits: font_size.to_bits(), x_bin, y_bin, }, diff --git a/src/edit/editor.rs b/src/edit/editor.rs index 900ce69..189aefb 100644 --- a/src/edit/editor.rs +++ b/src/edit/editor.rs @@ -424,14 +424,14 @@ impl<'a> Edit<'a> for Editor<'a> { self.buffer.set_redraw(true); } Action::PageUp => { - self.action(Action::Vertical(-self.buffer.size().1)); + self.action(Action::Vertical(-self.buffer.size().1 as i32)); } Action::PageDown => { - self.action(Action::Vertical(self.buffer.size().1)); + self.action(Action::Vertical(self.buffer.size().1 as i32)); } Action::Vertical(px) => { // TODO more efficient - let lines = px / self.buffer.metrics().line_height; + let lines = px / self.buffer.metrics().line_height as i32; if lines < 0 { for _ in 0..-lines { self.action(Action::Up); @@ -541,7 +541,7 @@ impl<'a> Edit<'a> for Editor<'a> { Action::Click { x, y } => { self.select_opt = None; - if let Some(new_cursor) = self.buffer.hit(x, y) { + if let Some(new_cursor) = self.buffer.hit(x as f32, y as f32) { if new_cursor != self.cursor { self.cursor = new_cursor; self.buffer.set_redraw(true); @@ -554,7 +554,7 @@ impl<'a> Edit<'a> for Editor<'a> { self.buffer.set_redraw(true); } - if let Some(new_cursor) = self.buffer.hit(x, y) { + if let Some(new_cursor) = self.buffer.hit(x as f32, y as f32) { if new_cursor != self.cursor { self.cursor = new_cursor; self.buffer.set_redraw(true); @@ -753,7 +753,7 @@ impl<'a> Edit<'a> for Editor<'a> { } else if let Some((min, max)) = range_opt.take() { f( min, - line_y - font_size, + (line_y - font_size) as i32, cmp::max(0, max - min) as u32, line_height as u32, Color::rgba(color.r(), color.g(), color.b(), 0x33), @@ -765,7 +765,7 @@ impl<'a> Edit<'a> for Editor<'a> { if run.glyphs.is_empty() && end.line > line_i { // Highlight all of internal empty lines - range_opt = Some((0, self.buffer.size().0)); + range_opt = Some((0, self.buffer.size().0 as i32)); } if let Some((mut min, mut max)) = range_opt.take() { @@ -774,12 +774,12 @@ impl<'a> Edit<'a> for Editor<'a> { if run.rtl { min = 0; } else { - max = self.buffer.size().0; + max = self.buffer.size().0 as i32; } } f( min, - line_y - font_size, + (line_y - font_size) as i32, cmp::max(0, max - min) as u32, line_height as u32, Color::rgba(color.r(), color.g(), color.b(), 0x33), @@ -815,7 +815,7 @@ impl<'a> Edit<'a> for Editor<'a> { }, }; - f(x, line_y - font_size, 1, line_height as u32, color); + f(x, (line_y - font_size) as i32, 1, line_height as u32, color); } for glyph in run.glyphs.iter() { @@ -827,7 +827,7 @@ impl<'a> Edit<'a> for Editor<'a> { }; cache.with_pixels(cache_key, glyph_color, |x, y, color| { - f(x_int + x, line_y + y_int + y, 1, 1, color); + f(x_int + x, line_y as i32 + y_int + y, 1, 1, color); }); } } diff --git a/src/edit/vi.rs b/src/edit/vi.rs index 5df0665..4785a0c 100644 --- a/src/edit/vi.rs +++ b/src/edit/vi.rs @@ -237,7 +237,7 @@ impl<'a> Edit<'a> for ViEditor<'a> { let cursor_glyph_opt = |cursor: &Cursor| -> Option<(usize, f32, f32)> { //TODO: better calculation of width - let default_width = (font_size as f32) / 2.0; + let default_width = font_size / 2.0; if cursor.line == line_i { for (glyph_i, glyph) in run.glyphs.iter().enumerate() { if cursor.index >= glyph.start && cursor.index < glyph.end { @@ -312,7 +312,7 @@ impl<'a> Edit<'a> for ViEditor<'a> { } else if let Some((min, max)) = range_opt.take() { f( min, - line_y - font_size, + (line_y - font_size) as i32, cmp::max(0, max - min) as u32, line_height as u32, Color::rgba(color.r(), color.g(), color.b(), 0x33), @@ -324,7 +324,7 @@ impl<'a> Edit<'a> for ViEditor<'a> { if run.glyphs.is_empty() && end.line > line_i { // Highlight all of internal empty lines - range_opt = Some((0, self.buffer().size().0)); + range_opt = Some((0, self.buffer().size().0 as i32)); } if let Some((mut min, mut max)) = range_opt.take() { @@ -333,12 +333,12 @@ impl<'a> Edit<'a> for ViEditor<'a> { if run.rtl { min = 0; } else { - max = self.buffer().size().0; + max = self.buffer().size().0 as i32; } } f( min, - line_y - font_size, + (line_y - font_size) as i32, cmp::max(0, max - min) as u32, line_height as u32, Color::rgba(color.r(), color.g(), color.b(), 0x33), @@ -397,13 +397,19 @@ impl<'a> Edit<'a> for ViEditor<'a> { let right_x = cmp::max(start_x, end_x); f( left_x, - line_y - font_size, + (line_y - font_size) as i32, (right_x - left_x) as u32, line_height as u32, Color::rgba(color.r(), color.g(), color.b(), 0x33), ); } else { - f(start_x, line_y - font_size, 1, line_height as u32, color); + f( + start_x, + (line_y - font_size) as i32, + 1, + line_height as u32, + color, + ); } } @@ -416,7 +422,7 @@ impl<'a> Edit<'a> for ViEditor<'a> { }; cache.with_pixels(cache_key, glyph_color, |x, y, color| { - f(x_int + x, line_y + y_int + y, 1, 1, color) + f(x_int + x, line_y as i32 + y_int + y, 1, 1, color); }); } } diff --git a/src/lib.rs b/src/lib.rs index 631f020..06ff8f9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,13 +21,13 @@ //! let mut swash_cache = SwashCache::new(&font_system); //! //! // Text metrics indicate the font size and line height of a buffer -//! let metrics = Metrics::new(14, 20); +//! let metrics = Metrics::new(14.0, 20.0); //! //! // A Buffer provides shaping and layout for a UTF-8 string, create one per text widget //! let mut buffer = Buffer::new(&font_system, metrics); //! //! // Set a size for the text buffer, in pixels -//! buffer.set_size(80, 25); +//! buffer.set_size(80.0, 25.0); //! //! // Attributes indicate what font to choose //! let attrs = Attrs::new(); diff --git a/src/shape.rs b/src/shape.rs index 762421c..6f43ab0 100644 --- a/src/shape.rs +++ b/src/shape.rs @@ -237,14 +237,14 @@ pub struct ShapeGlyph { impl ShapeGlyph { fn layout( &self, - font_size: i32, + font_size: f32, x: f32, y: f32, w: f32, level: unicode_bidi::Level, ) -> LayoutGlyph { - let x_offset = font_size as f32 * self.x_offset; - let y_offset = font_size as f32 * self.y_offset; + let x_offset = font_size * self.x_offset; + let y_offset = font_size * self.y_offset; let (cache_key, x_int, y_int) = CacheKey::new( self.font_id, @@ -608,8 +608,8 @@ impl ShapeLine { pub fn layout( &self, - font_size: i32, - line_width: i32, + font_size: f32, + line_width: f32, wrap: Wrap, align: Option, ) -> Vec { @@ -637,8 +637,8 @@ impl ShapeLine { // let mut vl_range_of_spans = Vec::with_capacity(1); let mut vl_range_of_spans: Vec = Vec::with_capacity(1); - let start_x = if self.rtl { line_width as f32 } else { 0.0 }; - let end_x = if self.rtl { 0.0 } else { line_width as f32 }; + let start_x = if self.rtl { line_width } else { 0.0 }; + let end_x = if self.rtl { 0.0 } else { line_width }; let mut x = start_x; let mut y; @@ -655,7 +655,7 @@ impl ShapeLine { .push((span_index, (0, 0), (span.words.len(), 0))); } } else { - let mut fit_x = line_width as f32; + let mut fit_x = line_width; for (span_index, span) in self.spans.iter().enumerate() { let mut word_ranges = Vec::new(); let mut word_range_width = 0.; @@ -666,7 +666,7 @@ impl ShapeLine { // incongruent directions let mut fitting_start = (span.words.len(), 0); for (i, word) in span.words.iter().enumerate().rev() { - let word_size = font_size as f32 * word.x_advance; + let word_size = font_size * word.x_advance; if fit_x - word_size >= 0. { // fits fit_x -= word_size; @@ -677,7 +677,7 @@ impl ShapeLine { continue; } else if wrap == Wrap::Glyph { for (glyph_i, glyph) in word.glyphs.iter().enumerate().rev() { - let glyph_size = font_size as f32 * glyph.x_advance; + let glyph_size = font_size * glyph.x_advance; if fit_x - glyph_size >= 0. { fit_x -= glyph_size; word_range_width += glyph_size; @@ -690,7 +690,7 @@ impl ShapeLine { number_of_blanks, )); number_of_blanks = 0; - fit_x = line_width as f32 - glyph_size; + fit_x = line_width - glyph_size; word_range_width = glyph_size; fitting_start = (i, glyph_i + 1); } @@ -706,8 +706,7 @@ impl ShapeLine { // previous word if it's a whitespace if previous_word.blank { number_of_blanks -= 1; - prev_word_width = - Some(previous_word.x_advance * font_size as f32); + prev_word_width = Some(previous_word.x_advance * font_size); } } if let Some(width) = prev_word_width { @@ -727,11 +726,11 @@ impl ShapeLine { } number_of_blanks = 0; if word.blank { - fit_x = line_width as f32; + fit_x = line_width; word_range_width = 0.; fitting_start = (i + 1, 0); } else { - fit_x = line_width as f32 - word_size; + fit_x = line_width - word_size; word_range_width = word_size; fitting_start = (i + 1, 0); } @@ -742,7 +741,7 @@ impl ShapeLine { // congruent direction let mut fitting_start = (0, 0); for (i, word) in span.words.iter().enumerate() { - let word_size = font_size as f32 * word.x_advance; + let word_size = font_size * word.x_advance; if fit_x - word_size >= 0. { // fits fit_x -= word_size; @@ -753,7 +752,7 @@ impl ShapeLine { continue; } else if wrap == Wrap::Glyph { for (glyph_i, glyph) in word.glyphs.iter().enumerate() { - let glyph_size = font_size as f32 * glyph.x_advance; + let glyph_size = font_size * glyph.x_advance; if fit_x - glyph_size >= 0. { fit_x -= glyph_size; word_range_width += glyph_size; @@ -766,7 +765,7 @@ impl ShapeLine { number_of_blanks, )); number_of_blanks = 0; - fit_x = line_width as f32 - glyph_size; + fit_x = line_width - glyph_size; word_range_width = glyph_size; fitting_start = (i, glyph_i); } @@ -782,8 +781,7 @@ impl ShapeLine { // previous word if it's a whitespace if previous_word.blank { number_of_blanks -= 1; - prev_word_width = - Some(previous_word.x_advance * font_size as f32); + prev_word_width = Some(previous_word.x_advance * font_size); } } if let Some(width) = prev_word_width { @@ -804,11 +802,11 @@ impl ShapeLine { number_of_blanks = 0; if word.blank { - fit_x = line_width as f32; + fit_x = line_width; word_range_width = 0.; fitting_start = (i + 1, 0); } else { - fit_x = line_width as f32 - word_size; + fit_x = line_width - word_size; word_range_width = word_size; fitting_start = (i, 0); } @@ -872,7 +870,7 @@ impl ShapeLine { } else { x += word_range_width; } - if word_range_width > line_width as f32 { + if word_range_width > line_width { // single word is bigger than line_width vl_range_of_spans.push(current_visual_line); current_visual_line = VisualLine::default(); @@ -895,15 +893,15 @@ impl ShapeLine { x = start_x; y = 0.; let alignment_correction = match (align, self.rtl) { - (Align::Left, true) => line_width as f32 - visual_line.w, + (Align::Left, true) => line_width - visual_line.w, (Align::Left, false) => 0., (Align::Right, true) => 0., - (Align::Right, false) => line_width as f32 - visual_line.w, - (Align::Center, _) => (line_width as f32 - visual_line.w) / 2.0, + (Align::Right, false) => line_width - visual_line.w, + (Align::Center, _) => (line_width - visual_line.w) / 2.0, (Align::Justified, _) => { // Don't justify the last line in a paragraph. if visual_line.spaces > 0 && index != number_of_visual_lines - 1 { - (line_width as f32 - visual_line.w) / visual_line.spaces as f32 + (line_width - visual_line.w) / visual_line.spaces as f32 } else { 0. } @@ -927,8 +925,8 @@ impl ShapeLine { [*starting_glyph..*ending_glyph] .iter() { - let x_advance = font_size as f32 * glyph.x_advance; - let y_advance = font_size as f32 * glyph.y_advance; + let x_advance = font_size * glyph.x_advance; + let y_advance = font_size * glyph.y_advance; x -= x_advance; if word_blank && align == Align::Justified { x -= alignment_correction; @@ -958,8 +956,8 @@ impl ShapeLine { let word_blank = word.blank; for glyph in &word.glyphs[g1..g2] { - let x_advance = font_size as f32 * glyph.x_advance; - let y_advance = font_size as f32 * glyph.y_advance; + let x_advance = font_size * glyph.x_advance; + let y_advance = font_size * glyph.y_advance; x -= x_advance; if word_blank && align == Align::Justified { x -= alignment_correction; @@ -1002,8 +1000,8 @@ impl ShapeLine { [*starting_glyph..*ending_glyph] .iter() { - let x_advance = font_size as f32 * glyph.x_advance; - let y_advance = font_size as f32 * glyph.y_advance; + let x_advance = font_size * glyph.x_advance; + let y_advance = font_size * glyph.y_advance; if word_blank && align == Align::Justified { glyphs.push(glyph.layout( font_size, @@ -1033,8 +1031,8 @@ impl ShapeLine { let word_blank = word.blank; for glyph in &word.glyphs[g1..g2] { - let x_advance = font_size as f32 * glyph.x_advance; - let y_advance = font_size as f32 * glyph.y_advance; + let x_advance = font_size * glyph.x_advance; + let y_advance = font_size * glyph.y_advance; if word_blank && align == Align::Justified { glyphs.push(glyph.layout( font_size, diff --git a/src/swash.rs b/src/swash.rs index cf88701..5e84354 100644 --- a/src/swash.rs +++ b/src/swash.rs @@ -31,7 +31,7 @@ fn swash_image( // Build the scaler let mut scaler = context .builder(font.as_swash()) - .size(cache_key.font_size as f32) + .size(f32::from_bits(cache_key.font_size_bits)) .hint(true) .build(); @@ -74,7 +74,7 @@ fn swash_outline_commands( // Build the scaler let mut scaler = context .builder(font.as_swash()) - .size(cache_key.font_size as f32) + .size(f32::from_bits(cache_key.font_size_bits)) .build(); // Scale the outline