diff --git a/frontends/rioterm/src/routes/assistant.rs b/frontends/rioterm/src/routes/assistant.rs index d2edc27f..b3782440 100644 --- a/frontends/rioterm/src/routes/assistant.rs +++ b/frontends/rioterm/src/routes/assistant.rs @@ -1,6 +1,5 @@ use rio_backend::error::{RioError, RioErrorLevel}; -use rio_backend::sugarloaf::components::rect::Rect; -use rio_backend::sugarloaf::Sugarloaf; +use rio_backend::sugarloaf::{Object, Rect, Sugarloaf, Text}; pub struct Assistant { pub inner: Option, @@ -41,66 +40,57 @@ pub fn screen(sugarloaf: &mut Sugarloaf, assistant: &Assistant) { let red = [1.0, 0.07058824, 0.38039216, 1.0]; let layout = sugarloaf.layout(); - let assistant_background = vec![ - // Rect { - // position: [30., 0.0], - // color: self.named_colors.background.0, - // size: [layout.width, layout.height], - // }, - Rect { - position: [0., 30.0], - color: blue, - size: [30., layout.height], - }, - Rect { - position: [15., layout.margin.top_y + 40.], - color: yellow, - size: [30., layout.height], - }, - Rect { - position: [30., layout.margin.top_y + 120.], - color: red, - size: [30., layout.height], - }, - ]; + let mut objects = Vec::with_capacity(8); - sugarloaf.append_rects(assistant_background); + objects.push(Object::Rect(Rect { + position: [0., 30.0], + color: blue, + size: [30., layout.height], + })); + objects.push(Object::Rect(Rect { + position: [15., layout.margin.top_y + 40.], + color: yellow, + size: [30., layout.height], + })); + objects.push(Object::Rect(Rect { + position: [30., layout.margin.top_y + 120.], + color: red, + size: [30., layout.height], + })); - sugarloaf.text( + objects.push(Object::Text(Text::single_line( (70., layout.margin.top_y + 50.), String::from("Woops! Rio got errors"), 28., [1., 1., 1., 1.], - true, - ); + ))); if let Some(report) = &assistant.inner { if report.level == RioErrorLevel::Error { - sugarloaf.text( + objects.push(Object::Text(Text::single_line( (70., layout.margin.top_y + 80.), String::from("after fix it, restart the terminal"), 18., [1., 1., 1., 1.], - true, - ); + ))); } if report.level == RioErrorLevel::Warning { - sugarloaf.text( + objects.push(Object::Text(Text::single_line( (70., layout.margin.top_y + 80.), String::from("(press enter twice to continue)"), 18., [1., 1., 1., 1.], - true, - ); + ))); } - sugarloaf.text( + objects.push(Object::Text(Text::multi_line( (70., layout.margin.top_y + 170.), report.report.to_string(), 14., [1., 1., 1., 1.], - false, - ); + ))); + + sugarloaf.set_objects(objects); } } diff --git a/frontends/rioterm/src/routes/dialog.rs b/frontends/rioterm/src/routes/dialog.rs index bd135bc3..7f31e649 100644 --- a/frontends/rioterm/src/routes/dialog.rs +++ b/frontends/rioterm/src/routes/dialog.rs @@ -1,5 +1,4 @@ -use rio_backend::sugarloaf::components::rect::Rect; -use rio_backend::sugarloaf::Sugarloaf; +use rio_backend::sugarloaf::{Object, Rect, Sugarloaf, Text}; #[inline] pub fn screen(sugarloaf: &mut Sugarloaf, content: &str) { @@ -11,54 +10,51 @@ pub fn screen(sugarloaf: &mut Sugarloaf, content: &str) { let layout = sugarloaf.layout(); let height = layout.height / layout.dimensions.scale; - let assistant_background = vec![ - Rect { - position: [0., 0.0], - color: black, - size: [layout.width, layout.height], - }, - Rect { - position: [0., 30.0], - color: blue, - size: [30., layout.height], - }, - Rect { - position: [15., layout.margin.top_y + 40.], - color: yellow, - size: [30., layout.height], - }, - Rect { - position: [30., layout.margin.top_y + 120.], - color: red, - size: [30., layout.height], - }, - ]; - - sugarloaf.append_rects(assistant_background); + let mut objects = Vec::with_capacity(7); + + objects.push(Object::Rect(Rect { + position: [0., 0.0], + color: black, + size: [layout.width, layout.height], + })); + objects.push(Object::Rect(Rect { + position: [0., 30.0], + color: blue, + size: [30., layout.height], + })); + objects.push(Object::Rect(Rect { + position: [15., layout.margin.top_y + 40.], + color: yellow, + size: [30., layout.height], + })); + objects.push(Object::Rect(Rect { + position: [30., layout.margin.top_y + 120.], + color: red, + size: [30., layout.height], + })); let mid_screen = height / 2.; - sugarloaf.text( + objects.push(Object::Text(Text::single_line( (70., mid_screen - 10.), content.to_string(), 48., [1., 1., 1., 1.], - true, - ); + ))); - sugarloaf.text( + objects.push(Object::Text(Text::single_line( (70., mid_screen + 30.), String::from("To quit press enter key"), 18., yellow, - true, - ); + ))); - sugarloaf.text( + objects.push(Object::Text(Text::single_line( (70., mid_screen + 50.), String::from("To continue press escape key"), 18., blue, - true, - ); + ))); + + sugarloaf.set_objects(objects); } diff --git a/frontends/rioterm/src/routes/welcome.rs b/frontends/rioterm/src/routes/welcome.rs index e130658f..ff03a0a3 100644 --- a/frontends/rioterm/src/routes/welcome.rs +++ b/frontends/rioterm/src/routes/welcome.rs @@ -1,5 +1,4 @@ -use rio_backend::sugarloaf::components::rect::Rect; -use rio_backend::sugarloaf::Sugarloaf; +use rio_backend::sugarloaf::{Object, Rect, Sugarloaf, Text}; #[inline] pub fn screen(sugarloaf: &mut Sugarloaf) { @@ -11,74 +10,69 @@ pub fn screen(sugarloaf: &mut Sugarloaf) { let layout = sugarloaf.layout(); let width = layout.width / layout.dimensions.scale; - let assistant_background = vec![ - Rect { - position: [0., 0.0], - color: black, - size: [layout.width, layout.height], - }, - Rect { - position: [0., 30.0], - color: blue, - size: [30., layout.height], - }, - Rect { - position: [15., layout.margin.top_y + 60.], - color: yellow, - size: [30., layout.height], - }, - Rect { - position: [30., layout.margin.top_y + 120.], - color: red, - size: [30., layout.height], - }, - ]; + let mut objects = Vec::with_capacity(7); - sugarloaf.append_rects(assistant_background); + objects.push(Object::Rect(Rect { + position: [0., 0.0], + color: black, + size: [layout.width, layout.height], + })); + objects.push(Object::Rect(Rect { + position: [0., 30.0], + color: blue, + size: [30., layout.height], + })); + objects.push(Object::Rect(Rect { + position: [15., layout.margin.top_y + 60.], + color: yellow, + size: [30., layout.height], + })); + objects.push(Object::Rect(Rect { + position: [30., layout.margin.top_y + 120.], + color: red, + size: [30., layout.height], + })); if width <= 440. { - sugarloaf.text( + objects.push(Object::Text(Text::single_line( (70., layout.margin.top_y + 50.), String::from("Welcome to\nRio Terminal"), 28., [1., 1., 1., 1.], - false, - ); + ))); - sugarloaf.text( + objects.push(Object::Text(Text::single_line( (70., layout.margin.top_y + 100.), String::from("(enter to continue)"), 18., yellow, - false, - ); + ))); return; } - sugarloaf.text( + objects.push(Object::Text(Text::single_line( (70., layout.margin.top_y + 50.), String::from("Welcome to Rio Terminal"), 28., [1., 1., 1., 1.], - true, - ); + ))); - sugarloaf.text( + objects.push(Object::Text(Text::single_line( (70., layout.margin.top_y + 80.), String::from("(press enter to continue)"), 18., yellow, - true, - ); + ))); - sugarloaf.text( + objects.push(Object::Text(Text::multi_line( (70., layout.margin.top_y + 220.), welcome_content(), 18., [1., 1., 1., 1.], - false, - ); + ))); + + sugarloaf.set_objects(objects); } #[inline] diff --git a/frontends/rioterm/src/screen/mod.rs b/frontends/rioterm/src/screen/mod.rs index 7390a75c..20f6ed05 100644 --- a/frontends/rioterm/src/screen/mod.rs +++ b/frontends/rioterm/src/screen/mod.rs @@ -200,7 +200,7 @@ impl Screen<'_> { window_id, 0, context_manager_config, - sugarloaf.layout_next(), + sugarloaf.layout(), sugarloaf_errors, )?; @@ -293,7 +293,7 @@ impl Screen<'_> { let padding_y_top = padding_top_from_config(config); self.sugarloaf.update_font(font_library); - self.sugarloaf.layout_next_mut().recalculate( + self.sugarloaf.layout_mut().recalculate( config.fonts.size, config.line_height, config.padding_x, @@ -301,7 +301,7 @@ impl Screen<'_> { padding_y_bottom, ); - self.sugarloaf.layout_next_mut().update(); + self.sugarloaf.layout_mut().update(); self.state = State::new(config, current_theme); for context in self.ctx().contexts() { @@ -366,7 +366,7 @@ impl Screen<'_> { // the next layout, so once the messenger.send_resize triggers // the wakeup from pty it will also trigger a sugarloaf.render() // and then eventually a render with the new layout computation. - let layout = self.sugarloaf.layout_next(); + let layout = self.sugarloaf.layout(); for context in self.ctx().contexts() { let mut terminal = context.terminal.lock(); terminal.resize::(layout); @@ -1192,8 +1192,8 @@ impl Screen<'_> { // If sugarloaf does have pending updates to process then // should abort current render - // let start = std::time::Instant::now(); - // println!("Render time elapsed"); + let start = std::time::Instant::now(); + println!("Render time elapsed"); let (rows, cursor, display_offset, has_blinking_enabled) = { let terminal = self.ctx().current().terminal.lock(); @@ -1229,8 +1229,8 @@ impl Screen<'_> { self.context_manager.schedule_render_on_route(800); } - // let duration = start.elapsed(); - // println!("Total render time is: {:?}\n", duration); + let duration = start.elapsed(); + println!("Total render time is: {:?}\n", duration); } fn sgr_mouse_report(&mut self, pos: Pos, button: u8, state: ElementState) { diff --git a/frontends/rioterm/src/state/mod.rs b/frontends/rioterm/src/state/mod.rs index bbe8fb66..2036d0ef 100644 --- a/frontends/rioterm/src/state/mod.rs +++ b/frontends/rioterm/src/state/mod.rs @@ -642,7 +642,7 @@ impl State { display_offset: i32, has_blinking_enabled: bool, ) { - let layout = sugarloaf.layout_next(); + let layout = sugarloaf.layout(); self.cursor.state = cursor; let mut is_cursor_visible = self.cursor.state.is_visible(); @@ -687,16 +687,16 @@ impl State { context_manager.len(), ); - sugarloaf.append_rects(self.navigation.rects.to_owned()); - - for text in self.navigation.texts.iter() { - sugarloaf.text( - text.position, - text.content.to_owned(), - text.font_size, - text.color, - true, - ); - } + sugarloaf.set_objects(self.navigation.objects.clone()); + + // for text in self.navigation.texts.iter() { + // sugarloaf.text( + // text.position, + // text.content.to_owned(), + // text.font_size, + // text.color, + // true, + // ); + // } } } diff --git a/frontends/rioterm/src/state/navigation.rs b/frontends/rioterm/src/state/navigation.rs index 66e72b3a..5e29c0cf 100644 --- a/frontends/rioterm/src/state/navigation.rs +++ b/frontends/rioterm/src/state/navigation.rs @@ -1,32 +1,8 @@ use crate::constants::*; use rio_backend::config::navigation::NavigationMode; -use rio_backend::sugarloaf::components::rect::Rect; +use rio_backend::sugarloaf::{Object, Rect, Text}; use std::collections::HashMap; -pub struct Text { - pub position: (f32, f32), - pub content: String, - pub font_size: f32, - pub color: [f32; 4], -} - -impl Text { - #[inline] - pub fn new( - position: (f32, f32), - content: String, - font_size: f32, - color: [f32; 4], - ) -> Self { - Text { - position, - content, - font_size, - color, - } - } -} - pub struct ScreenNavigationColors { foreground: [f32; 4], active: [f32; 4], @@ -35,8 +11,7 @@ pub struct ScreenNavigationColors { pub struct ScreenNavigation { pub mode: NavigationMode, - pub rects: Vec, - pub texts: Vec, + pub objects: Vec, keys: String, current: usize, colors: ScreenNavigationColors, @@ -65,8 +40,7 @@ impl ScreenNavigation { ScreenNavigation { mode, - rects: vec![], - texts: vec![], + objects: vec![], keys: String::from(""), color_automation, current: 0, @@ -118,8 +92,7 @@ impl ScreenNavigation { return; } - self.rects = vec![]; - self.texts = vec![]; + self.objects = vec![]; match self.mode { #[cfg(target_os = "macos")] @@ -172,7 +145,7 @@ impl ScreenNavigation { size: [30.0, size], }; initial_position -= position_modifier; - self.rects.push(renderable); + self.objects.push(Object::Rect(renderable)); } } @@ -216,22 +189,22 @@ impl ScreenNavigation { size: [200., 26.0], }; - self.texts.push(Text::new( + self.objects.push(Object::Text(Text::single_line( (initial_position - 12., 14.5), "".to_string(), 23., icon_color, - )); + ))); - self.texts.push(Text::new( + self.objects.push(Object::Text(Text::single_line( (initial_position + 4., 13.0), format!("{}.{}", current_index + 1, main_name), 14., fg_color, - )); + ))); initial_position -= position_modifier; - self.rects.push(renderable); + self.objects.push(Object::Rect(renderable)); if len <= 1 { return; @@ -246,12 +219,12 @@ impl ScreenNavigation { if min_view == 1 { if len > 1 { - self.texts.push(Text::new( + self.objects.push(Object::Text(Text::single_line( (initial_position + 36., 13.0), format!("+ {}", len - 1), 13., self.colors.foreground, - )); + ))); } } else { let mut rendered = len - 1; @@ -261,12 +234,12 @@ impl ScreenNavigation { } if initial_position <= 120.0 { - self.texts.push(Text::new( + self.objects.push(Object::Text(Text::single_line( (initial_position + 36., 13.0), format!("+ {}", rendered), 13., self.colors.foreground, - )); + ))); break; } @@ -299,22 +272,22 @@ impl ScreenNavigation { size: [160., 26.], }; - self.texts.push(Text::new( + self.objects.push(Object::Text(Text::single_line( (initial_position - 12., 15.0), "".to_string(), 22., icon_color, - )); + ))); - self.texts.push(Text::new( + self.objects.push(Object::Text(Text::single_line( (initial_position + 4., 13.0), format!("{}.{}", iterator + 1, name), 14., fg_color, - )); + ))); initial_position -= position_modifier; - self.rects.push(renderable_item); + self.objects.push(Object::Rect(renderable_item)); if len - 1 == iterator { iterator = 0; @@ -343,7 +316,7 @@ impl ScreenNavigation { size: [self.width * (self.scale + 1.0), 22.0], }; - self.rects.push(renderable); + self.objects.push(Object::Rect(renderable)); let iter = 0..len; let mut tabs = Vec::from_iter(iter); @@ -400,15 +373,15 @@ impl ScreenNavigation { size: [120. + name_modifier + 30., 22.], }; - self.texts.push(Text::new( + self.objects.push(Object::Text(Text::single_line( (initial_position_x + 4., position_y + text_pos_mod), format!("{}.{}", i + 1, name), 14., foreground_color, - )); + ))); initial_position_x += name_modifier; - self.rects.push(renderable_item); + self.objects.push(Object::Rect(renderable_item)); } } } diff --git a/misc/scripts/underlines.sh b/misc/scripts/underlines.sh index 2b3e673f..f2c40670 100644 --- a/misc/scripts/underlines.sh +++ b/misc/scripts/underlines.sh @@ -1,5 +1,5 @@ # Script retired from https://github.com/pop-os/cosmic-term/blob/be808b56cf24d03fc99cf44b0885078a81a16523/ansi-colors.sh#L64 -# which licensed under GNU 3.0 https://github.com/pop-os/cosmic-term/blob/master/LICENSE +# which licensed under GNU 3.0 https://github.com/pop-os/cosmic-term/blob/master/LICENSE #!/usr/bin/env bash @@ -30,7 +30,7 @@ printf "\n" printf "INV: " printf "\033[7m\033[9mStrikeout\033[0m " -printf "\033[7m\033[4mUnderline\033[0m " +printf "\033[7m\033[4mUngderline\033[0m " printf "\033[7m\033[4:2mDoubleUnderline\033[0m " printf "\033[7m\033[4:3mCurlyUnderline\033[0m " printf "\033[7m\033[4:4mDottedUnderline\033[0m " @@ -52,4 +52,4 @@ do printf "\033[58:5:"${line_color}m printf "\033[4:5mDashedUnderline\033[0m " printf "\n" -done \ No newline at end of file +done diff --git a/sugarloaf/examples/rect.rs b/sugarloaf/examples/rect.rs index 55426f86..52daa197 100644 --- a/sugarloaf/examples/rect.rs +++ b/sugarloaf/examples/rect.rs @@ -4,7 +4,7 @@ extern crate tokio; use raw_window_handle::{HasDisplayHandle, HasWindowHandle}; use sugarloaf::components::rect::Rect; use sugarloaf::layout::SugarloafLayout; -use sugarloaf::{Sugarloaf, SugarloafWindow, SugarloafWindowSize}; +use sugarloaf::{Object, Sugarloaf, SugarloafWindow, SugarloafWindowSize}; use winit::event_loop::ControlFlow; use winit::platform::run_on_demand::EventLoopExtRunOnDemand; use winit::{ @@ -65,6 +65,33 @@ async fn main() { let _ = event_loop.run_on_demand(move |event, event_loop_window_target| { event_loop_window_target.set_control_flow(ControlFlow::Wait); + let mut objects = Vec::with_capacity(5); + objects.push(Object::Rect(Rect { + position: [10.0, 10.0], + color: [1.0, 1.0, 1.0, 1.0], + size: [1.0, 1.0], + })); + objects.push(Object::Rect(Rect { + position: [15.0, 10.0], + color: [1.0, 1.0, 1.0, 1.0], + size: [10.0, 10.0], + })); + objects.push(Object::Rect(Rect { + position: [30.0, 20.0], + color: [1.0, 1.0, 0.0, 1.0], + size: [50.0, 50.0], + })); + objects.push(Object::Rect(Rect { + position: [200., 200.0], + color: [0.0, 1.0, 0.0, 1.0], + size: [100.0, 100.0], + })); + objects.push(Object::Rect(Rect { + position: [500.0, 200.0], + color: [1.0, 1.0, 0.0, 1.0], + size: [200.0, 200.0], + })); + match event { Event::Resumed => { window.request_redraw(); @@ -79,63 +106,12 @@ async fn main() { let new_inner_size = window.inner_size(); sugarloaf.rescale(scale_factor as f32); sugarloaf.resize(new_inner_size.width, new_inner_size.height); - sugarloaf.append_rects(vec![ - Rect { - position: [10.0, 10.0], - color: [1.0, 1.0, 1.0, 1.0], - size: [1.0, 1.0], - }, - Rect { - position: [15.0, 10.0], - color: [1.0, 1.0, 1.0, 1.0], - size: [10.0, 10.0], - }, - Rect { - position: [30.0, 20.0], - color: [1.0, 1.0, 0.0, 1.0], - size: [50.0, 50.0], - }, - Rect { - position: [200., 200.0], - color: [0.0, 1.0, 0.0, 1.0], - size: [100.0, 100.0], - }, - Rect { - position: [500.0, 200.0], - color: [1.0, 1.0, 0.0, 1.0], - size: [200.0, 200.0], - }, - ]); + + sugarloaf.set_objects(objects); sugarloaf.render(); } WindowEvent::RedrawRequested { .. } => { - sugarloaf.append_rects(vec![ - Rect { - position: [10.0, 10.0], - color: [1.0, 1.0, 1.0, 1.0], - size: [1.0, 1.0], - }, - Rect { - position: [15.0, 10.0], - color: [1.0, 1.0, 1.0, 1.0], - size: [10.0, 10.0], - }, - Rect { - position: [30.0, 20.0], - color: [1.0, 1.0, 0.0, 1.0], - size: [50.0, 50.0], - }, - Rect { - position: [200., 200.0], - color: [0.0, 1.0, 0.0, 1.0], - size: [100.0, 100.0], - }, - Rect { - position: [500.0, 200.0], - color: [1.0, 1.0, 0.0, 1.0], - size: [200.0, 200.0], - }, - ]); + sugarloaf.set_objects(objects); sugarloaf.render(); } _ => (), diff --git a/sugarloaf/examples/transparent.rs b/sugarloaf/examples/transparent.rs index 2ec18601..0803d7d7 100644 --- a/sugarloaf/examples/transparent.rs +++ b/sugarloaf/examples/transparent.rs @@ -4,7 +4,7 @@ extern crate tokio; use raw_window_handle::{HasDisplayHandle, HasWindowHandle}; use sugarloaf::components::rect::Rect; use sugarloaf::layout::SugarloafLayout; -use sugarloaf::{Sugarloaf, SugarloafWindow, SugarloafWindowSize}; +use sugarloaf::{Object, Sugarloaf, SugarloafWindow, SugarloafWindowSize}; use winit::event::WindowEvent; use winit::event_loop::ControlFlow; use winit::platform::run_on_demand::EventLoopExtRunOnDemand; @@ -71,18 +71,20 @@ async fn main() { } Event::WindowEvent { event, .. } => { if let WindowEvent::RedrawRequested { .. } = event { - sugarloaf.append_rects(vec![ - Rect { + let objects = vec![ + Object::Rect(Rect { position: [10.0, 10.0], color: [1.0, 0.0, 1.0, 0.2], size: [100.0, 100.0], - }, - Rect { + }), + Object::Rect(Rect { position: [115.0, 10.0], color: [0.0, 1.0, 1.0, 0.5], size: [100.0, 100.0], - }, - ]); + }), + ]; + + sugarloaf.set_objects(objects); sugarloaf.render(); } } diff --git a/sugarloaf/src/lib.rs b/sugarloaf/src/lib.rs index 18e13db5..4a1142d0 100644 --- a/sugarloaf/src/lib.rs +++ b/sugarloaf/src/lib.rs @@ -15,6 +15,7 @@ pub use crate::sugarloaf::{ Sugarloaf, SugarloafErrors, SugarloafRenderer, SugarloafWindow, SugarloafWindowSize, SugarloafWithErrors, }; +pub use components::rect::Rect; pub use layout::{ Content, ContentBuilder, FragmentStyle, FragmentStyleDecoration, UnderlineInfo, UnderlineShape, diff --git a/sugarloaf/src/sugarloaf.rs b/sugarloaf/src/sugarloaf.rs index 33b4ae90..5fd24e53 100644 --- a/sugarloaf/src/sugarloaf.rs +++ b/sugarloaf/src/sugarloaf.rs @@ -11,7 +11,7 @@ use crate::components::text; use crate::font::{fonts::SugarloafFont, FontLibrary}; use crate::layout::SugarloafLayout; use crate::sugarloaf::layer::types; -use crate::{context::Context, Content, SugarBlock, SugarText}; +use crate::{context::Context, Content, Object}; use ab_glyph::{self, PxScale}; use core::fmt::{Debug, Formatter}; use primitives::ImageProperties; @@ -167,13 +167,9 @@ impl Sugarloaf<'_> { } #[inline] - pub fn layout_next(&self) -> SugarloafLayout { - self.state.next.layout - } - - #[inline] - pub fn layout_next_mut(&mut self) -> &mut SugarloafLayout { - &mut self.state.next.layout + pub fn layout_mut(&mut self) -> &mut SugarloafLayout { + self.state.mark_dirty(); + &mut self.state.current.layout } #[inline] @@ -203,13 +199,13 @@ impl Sugarloaf<'_> { } #[inline] - pub fn append_rects(&mut self, rects: Vec) { - self.state.compute_block(SugarBlock { rects, text: None }); + pub fn set_objects(&mut self, objects: Vec) { + self.state.compute_objects(objects); } #[inline] pub fn set_content(&mut self, content: Content) { - self.state.next.content = content; + self.state.set_content(content); } #[inline] @@ -217,27 +213,27 @@ impl Sugarloaf<'_> { self.state.clean_screen(); } - #[inline] - pub fn text( - &mut self, - position: (f32, f32), - content: String, - font_size: f32, - color: [f32; 4], - single_line: bool, - ) { - self.state.compute_block(SugarBlock { - rects: vec![], - text: Some(SugarText { - position, - content, - font_id: 0, - font_size, - color, - single_line, - }), - }); - } + // #[inline] + // pub fn text( + // &mut self, + // position: (f32, f32), + // content: String, + // font_size: f32, + // color: [f32; 4], + // single_line: bool, + // ) { + // self.state.compute_block(SugarBlock { + // rects: vec![], + // text: Some(SugarText { + // position, + // content, + // font_id: 0, + // font_size, + // color, + // single_line, + // }), + // }); + // } #[inline] pub fn resize(&mut self, width: u32, height: u32) { @@ -268,7 +264,7 @@ impl Sugarloaf<'_> { #[inline] pub fn mark_dirty(&mut self) { - self.state.is_dirty = true; + self.state.mark_dirty(); } #[inline] diff --git a/sugarloaf/src/sugarloaf/compositors/advanced.rs b/sugarloaf/src/sugarloaf/compositors/advanced.rs index d2cbd6de..94300d40 100644 --- a/sugarloaf/src/sugarloaf/compositors/advanced.rs +++ b/sugarloaf/src/sugarloaf/compositors/advanced.rs @@ -13,7 +13,6 @@ use crate::sugarloaf::state::SugarTree; pub struct Advanced { pub render_data: RenderData, pub mocked_render_data: RenderData, - content: Content, layout_context: LayoutContext, } @@ -21,7 +20,6 @@ impl Advanced { pub fn new(font_library: &FontLibrary) -> Self { Self { layout_context: LayoutContext::new(font_library), - content: Content::default(), render_data: RenderData::new(), mocked_render_data: RenderData::new(), } @@ -29,14 +27,12 @@ impl Advanced { #[inline] pub fn reset(&mut self) { - self.content = Content::default(); self.render_data = RenderData::default(); self.layout_context.clear_cache(); } #[inline] pub fn clean(&mut self) { - self.content = Content::default(); self.render_data = RenderData::default(); } @@ -104,9 +100,4 @@ impl Advanced { .break_lines() .break_without_advance_or_alignment() } - - #[inline] - pub fn set_content(&mut self, content: Content) { - self.content = content; - } } diff --git a/sugarloaf/src/sugarloaf/compositors/elementary.rs b/sugarloaf/src/sugarloaf/compositors/elementary.rs index ba9e8888..4641a950 100644 --- a/sugarloaf/src/sugarloaf/compositors/elementary.rs +++ b/sugarloaf/src/sugarloaf/compositors/elementary.rs @@ -6,7 +6,8 @@ use crate::components::text::glyph::OwnedSection; use crate::sugarloaf::graphics; use crate::sugarloaf::state::SugarTree; -use crate::sugarloaf::{PxScale, Rect, SugarText}; +use crate::sugarloaf::{PxScale, Rect}; +use crate::Text; #[allow(unused)] struct GraphicRect { @@ -50,7 +51,7 @@ impl Elementary { #[inline] pub fn create_section_from_text( &mut self, - sugar_text: &SugarText, + sugar_text: &Text, tree: &SugarTree, ) -> OwnedSection { let text = crate::components::text::OwnedText { diff --git a/sugarloaf/src/sugarloaf/primitives.rs b/sugarloaf/src/sugarloaf/primitives.rs index d4f0c986..62f97995 100644 --- a/sugarloaf/src/sugarloaf/primitives.rs +++ b/sugarloaf/src/sugarloaf/primitives.rs @@ -37,7 +37,7 @@ pub struct ImageProperties { } #[derive(Default, Debug, PartialEq, Clone)] -pub struct SugarText { +pub struct Text { pub position: (f32, f32), pub content: String, pub font_id: usize, @@ -46,8 +46,44 @@ pub struct SugarText { pub single_line: bool, } -#[derive(Clone, Default, Debug, PartialEq)] -pub struct SugarBlock { - pub rects: Vec, - pub text: Option, +impl Text { + #[inline] + pub fn single_line( + position: (f32, f32), + content: String, + font_size: f32, + color: [f32; 4], + ) -> Self { + Text { + position, + content, + font_size, + font_id: 0, + color, + single_line: true, + } + } + + #[inline] + pub fn multi_line( + position: (f32, f32), + content: String, + font_size: f32, + color: [f32; 4], + ) -> Self { + Text { + position, + content, + font_size, + font_id: 0, + color, + single_line: false, + } + } +} + +#[derive(Clone, Debug, PartialEq)] +pub enum Object { + Rect(Rect), + Text(Text), } diff --git a/sugarloaf/src/sugarloaf/state.rs b/sugarloaf/src/sugarloaf/state.rs index b0a3b19e..741bec23 100644 --- a/sugarloaf/src/sugarloaf/state.rs +++ b/sugarloaf/src/sugarloaf/state.rs @@ -7,13 +7,25 @@ use super::compositors::SugarCompositors; use super::graphics::SugarloafGraphics; use crate::font::FontLibrary; use crate::sugarloaf::{text, RectBrush, RichTextBrush, SugarloafLayout}; -use crate::{Content, SugarBlock}; +use crate::{Content, Object}; + +#[derive(Debug, PartialEq)] +pub enum SugarTreeDiff { + Equal, + Different, + Repaint, +} + +#[derive(Clone, Default)] +pub struct SugarTree { + pub content: Content, + pub objects: Vec, + pub layout: SugarloafLayout, +} pub struct SugarState { - pub current: Box, - pub next: SugarTree, + pub current: SugarTree, latest_change: SugarTreeDiff, - pub is_dirty: bool, pub compositors: SugarCompositors, // TODO: Decide if graphics should be in SugarTree or SugarState pub graphics: SugarloafGraphics, @@ -25,19 +37,15 @@ impl SugarState { font_library: &FontLibrary, font_features: &Option>, ) -> SugarState { - // First time computing changes should obtain dimensions - let next = SugarTree { - layout: initial_layout, - ..Default::default() - }; - let mut state = SugarState { - is_dirty: false, compositors: SugarCompositors::new(font_library), graphics: SugarloafGraphics::default(), - current: Box::::default(), - next, - latest_change: SugarTreeDiff::LayoutIsDifferent, + // First time computing changes should obtain dimensions + current: SugarTree { + layout: initial_layout, + ..Default::default() + }, + latest_change: SugarTreeDiff::Repaint, }; state.compositors.advanced.set_font_features(font_features); @@ -46,7 +54,8 @@ impl SugarState { #[inline] pub fn compute_layout_resize(&mut self, width: u32, height: u32) { - self.next.layout.resize(width, height).update(); + self.current.layout.resize(width, height).update(); + self.latest_change = SugarTreeDiff::Repaint; } #[inline] @@ -54,62 +63,80 @@ impl SugarState { // In rescale case, we actually need to clean cache from the compositors // because it's based on sugarline hash which only consider the font size self.compositors.advanced.reset(); - self.next.layout.rescale(scale).update(); + self.current.layout.rescale(scale).update(); + self.latest_change = SugarTreeDiff::Repaint; } #[inline] pub fn compute_layout_font_size(&mut self, operation: u8) { let should_update = match operation { - 0 => self.next.layout.reset_font_size(), - 2 => self.next.layout.increase_font_size(), - 1 => self.next.layout.decrease_font_size(), + 0 => self.current.layout.reset_font_size(), + 2 => self.current.layout.increase_font_size(), + 1 => self.current.layout.decrease_font_size(), _ => false, }; if should_update { - self.next.layout.update(); + self.current.layout.update(); + self.latest_change = SugarTreeDiff::Repaint; } } #[inline] - pub fn set_content(&mut self, content: Content) { - self.compositors.advanced.set_content(content); + pub fn set_content(&mut self, new_content: Content) { + if self.current.content != new_content { + self.latest_change = SugarTreeDiff::Different; + } + self.current.content = new_content; } #[inline] pub fn set_fonts(&mut self, fonts: &FontLibrary) { self.compositors.advanced.set_fonts(fonts); - self.next.layout.dimensions.height = 0.0; - self.next.layout.dimensions.width = 0.0; + self.current.layout.dimensions.height = 0.0; + self.current.layout.dimensions.width = 0.0; + self.latest_change = SugarTreeDiff::Repaint; } #[inline] pub fn set_font_features(&mut self, font_features: &Option>) { self.compositors.advanced.set_font_features(font_features); + self.latest_change = SugarTreeDiff::Repaint; + } + + #[inline] + pub fn mark_dirty(&mut self) { + self.latest_change = SugarTreeDiff::Different; } #[inline] pub fn clean_screen(&mut self) { self.current.content.clear(); - self.current.blocks.clear(); + self.current.objects.clear(); self.compositors.advanced.reset(); } #[inline] - pub fn compute_block(&mut self, block: SugarBlock) { + pub fn compute_objects(&mut self, new_objects: Vec) { + if self.current.objects == new_objects { + self.latest_change = SugarTreeDiff::Different; + }; + // Block are used only with elementary renderer - self.next.blocks.push(block); + self.current.objects = new_objects; } #[inline] pub fn reset_compositor(&mut self) { self.compositors.elementary.clean(); self.compositors.advanced.reset(); + self.latest_change = SugarTreeDiff::Equal; } #[inline] pub fn clean_compositor(&mut self) { self.compositors.elementary.clean(); + self.latest_change = SugarTreeDiff::Equal; } #[inline] @@ -121,7 +148,7 @@ impl SugarState { context: &mut super::Context, ) -> bool { #[cfg(not(feature = "always_dirty"))] - if !self.is_dirty && self.latest_change == SugarTreeDiff::Equal { + if self.latest_change == SugarTreeDiff::Equal { self.compositors.advanced.clean(); return false; } @@ -133,22 +160,23 @@ impl SugarState { } // Elementary renderer is used for everything else in sugarloaf - // like blocks rendering (created by .text() or .append_rects()) + // like objects rendering (created by .text() or .append_rects()) // ... - // If current tree has blocks and compositor has empty blocks - // It means that's either the first render or blocks were erased on compute_diff() step - for block in &self.current.blocks { - if let Some(text) = &block.text { - elementary_brush.queue( - &self - .compositors - .elementary - .create_section_from_text(text, &self.current), - ); - } - - if !block.rects.is_empty() { - self.compositors.elementary.rects.extend(&block.rects); + // If current tree has objects and compositor has empty objects + // It means that's either the first render or objects were erased on compute_diff() step + for object in &self.current.objects { + match object { + Object::Text(text) => { + elementary_brush.queue( + &self + .compositors + .elementary + .create_section_from_text(text, &self.current), + ); + } + Object::Rect(rect) => { + self.compositors.elementary.rects.push(*rect); + } } } @@ -161,7 +189,7 @@ impl SugarState { // then current will flip with next and will try to obtain // the dimensions. - if self.latest_change != SugarTreeDiff::LayoutIsDifferent { + if self.latest_change != SugarTreeDiff::Repaint { return; } @@ -184,29 +212,17 @@ impl SugarState { if dimensions_changed { self.current.layout.update(); - self.next.layout = self.current.layout; - self.is_dirty = true; log::info!("sugar_state: dimensions has changed"); } } } - #[inline] - pub fn reset_next(&mut self) { - self.next.layout = self.current.layout; - self.next.content.clear(); - self.next.blocks.clear(); - self.is_dirty = false; - } - #[inline] pub fn compute_changes(&mut self) { // If sugar dimensions are empty then need to find it if self.current.layout.dimensions.width == 0.0 || self.current.layout.dimensions.height == 0.0 { - self.current = Box::new(std::mem::take(&mut self.next)); - self.compositors .advanced .calculate_dimensions(&self.current); @@ -214,8 +230,7 @@ impl SugarState { self.compositors.advanced.update_layout(&self.current); self.compositors.elementary.set_should_resize(); - self.reset_next(); - self.latest_change = SugarTreeDiff::LayoutIsDifferent; + self.latest_change = SugarTreeDiff::Repaint; log::info!("has empty dimensions, will try to find..."); return; } @@ -224,15 +239,11 @@ impl SugarState { let mut should_resize = false; let mut should_compute_dimensions = false; - self.latest_change = - self.current - .calculate_diff(&self.next, false, self.is_dirty); - match &self.latest_change { SugarTreeDiff::Equal => { // Do nothing } - SugarTreeDiff::LayoutIsDifferent => { + SugarTreeDiff::Repaint => { should_update = true; should_compute_dimensions = true; should_resize = true; @@ -245,8 +256,6 @@ impl SugarState { log::info!("state compute_changes result: {:?}", self.latest_change); if should_update { - self.current = Box::new(std::mem::take(&mut self.next)); - if should_compute_dimensions { self.compositors .advanced @@ -259,48 +268,6 @@ impl SugarState { if should_resize { self.compositors.elementary.set_should_resize(); } - - self.reset_next(); - } -} - -#[derive(Debug, PartialEq)] -pub enum SugarTreeDiff { - Equal, - Different, - LayoutIsDifferent, -} - -#[derive(Clone, Default)] -pub struct SugarTree { - pub content: Content, - pub blocks: Vec, - pub layout: SugarloafLayout, -} - -impl SugarTree { - #[inline] - pub fn calculate_diff( - &self, - next: &SugarTree, - _exact: bool, - is_dirty: bool, - ) -> SugarTreeDiff { - if self.layout != next.layout { - // In layout case, doesn't matter if blocks are different - // or texts are different, it will repaint everything - return SugarTreeDiff::LayoutIsDifferent; - } - - if is_dirty || self.blocks != next.blocks { - return SugarTreeDiff::Different; - } - - if self.content != next.content { - return SugarTreeDiff::Different; - } - - SugarTreeDiff::Equal } }