Skip to content

Commit

Permalink
Merge pull request #642 from Sharktheone/renderer/reload
Browse files Browse the repository at this point in the history
Tab reloading!
  • Loading branch information
Sharktheone authored Oct 21, 2024
2 parents 2728bcc + 498fc18 commit 8a01d75
Show file tree
Hide file tree
Showing 11 changed files with 205 additions and 68 deletions.
4 changes: 4 additions & 0 deletions crates/gosub_net/src/http/fetcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ impl Fetcher {
}
}

pub fn base(&self) -> &Url {
&self.base_url
}

pub async fn get_url(&self, url: &Url) -> Result<Response> {
let scheme = url.scheme();

Expand Down
8 changes: 7 additions & 1 deletion crates/gosub_render_backend/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ use crate::layout::TextLayout;
use crate::svg::SvgRenderer;
pub use geo::*;
use gosub_shared::async_executor::WasmNotSendSync;
use gosub_shared::traits::css3::CssSystem;
use gosub_shared::traits::render_tree::RenderTree;
use gosub_shared::types::Result;
use raw_window_handle::{HasDisplayHandle, HasWindowHandle};
use smallvec::SmallVec;
Expand All @@ -17,10 +19,14 @@ pub trait WindowHandle: HasDisplayHandle + HasWindowHandle + Send + Sync + Clone

impl<T> WindowHandle for T where T: HasDisplayHandle + HasWindowHandle + Send + Sync + Clone {}

pub trait WindowedEventLoop<B: RenderBackend>: WasmNotSendSync + Clone + 'static {
pub trait WindowedEventLoop<B: RenderBackend, RT: RenderTree<C>, C: CssSystem>:
WasmNotSendSync + Clone + 'static
{
fn redraw(&mut self);

fn add_img_cache(&mut self, url: String, buf: ImageBuffer<B>, size: Option<SizeU32>);

fn reload_from(&mut self, rt: RT);
}

pub trait RenderBackend: Sized + Debug + 'static {
Expand Down
91 changes: 75 additions & 16 deletions crates/gosub_renderer/src/draw.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::debug::scale::px_scale;
use crate::draw::img::request_img;
use crate::draw::img_cache::ImageCache;
use crate::render_tree::{load_html_rendertree, TreeDrawer};
use crate::render_tree::{load_html_rendertree, load_html_rendertree_fetcher, TreeDrawer};
use anyhow::anyhow;
use gosub_net::http::fetcher::Fetcher;
use gosub_render_backend::geo::{Size, SizeU32, FP};
Expand All @@ -18,18 +18,26 @@ use gosub_shared::node::NodeId;
use gosub_shared::traits::css3::{CssProperty, CssPropertyMap, CssSystem};
use gosub_shared::traits::document::Document;
use gosub_shared::traits::html5::Html5Parser;
use gosub_shared::traits::render_tree;
use gosub_shared::types::Result;
use log::warn;
use log::{error, info, warn};
use std::future::Future;
use std::marker::PhantomData;
use std::sync::mpsc::Sender;
use std::sync::{Arc, Mutex};
use url::Url;

mod img;
pub mod img_cache;

pub trait SceneDrawer<B: RenderBackend, L: Layouter, LT: LayoutTree<L>, D: Document<C>, C: CssSystem>:
WasmNotSend + 'static
pub trait SceneDrawer<
B: RenderBackend,
L: Layouter,
LT: LayoutTree<L>,
D: Document<C>,
C: CssSystem,
RT: render_tree::RenderTree<C>,
>: WasmNotSend + 'static
{
type ImgCache: ImgCache<B>;

Expand All @@ -38,7 +46,7 @@ pub trait SceneDrawer<B: RenderBackend, L: Layouter, LT: LayoutTree<L>, D: Docum
backend: &mut B,
data: &mut B::WindowData<'_>,
size: SizeU32,
el: &impl WindowedEventLoop<B>,
el: &impl WindowedEventLoop<B, RT, C>,
) -> bool;
fn mouse_move(&mut self, backend: &mut B, x: FP, y: FP) -> bool;

Expand All @@ -63,6 +71,10 @@ pub trait SceneDrawer<B: RenderBackend, L: Layouter, LT: LayoutTree<L>, D: Docum
fn make_dirty(&mut self);

fn delete_scene(&mut self);

fn reload<P: Html5Parser<C, Document = D>>(&mut self, el: impl WindowedEventLoop<B, RT, C>);

fn reload_from(&mut self, tree: RT);
}

const DEBUG_CONTENT_COLOR: (u8, u8, u8) = (0, 192, 255); //rgb(0, 192, 255)
Expand All @@ -72,8 +84,8 @@ const DEBUG_BORDER_COLOR: (u8, u8, u8) = (255, 72, 72); //rgb(255, 72, 72)

type Point = gosub_shared::types::Point<FP>;

impl<B: RenderBackend, L: Layouter, D: Document<C>, C: CssSystem> SceneDrawer<B, L, RenderTree<L, C>, D, C>
for TreeDrawer<B, L, D, C>
impl<B: RenderBackend, L: Layouter, D: Document<C>, C: CssSystem>
SceneDrawer<B, L, RenderTree<L, C>, D, C, RenderTree<L, C>> for TreeDrawer<B, L, D, C>
where
<<B as RenderBackend>::Text as Text>::Font: From<<<L as Layouter>::TextLayout as TextLayout>::Font>,
{
Expand All @@ -84,7 +96,7 @@ where
backend: &mut B,
data: &mut B::WindowData<'_>,
size: SizeU32,
el: &impl WindowedEventLoop<B>,
el: &impl WindowedEventLoop<B, RenderTree<L, C>, C>,
) -> bool {
if !self.dirty && self.size == Some(size) {
return false;
Expand Down Expand Up @@ -113,6 +125,7 @@ where
drawer: self,
svg: Arc::new(Mutex::new(B::SVGRenderer::new())),
el,
_marker: PhantomData,
};

drawer.render(size);
Expand Down Expand Up @@ -265,17 +278,63 @@ where
self.tree_scene = None;
self.debugger_scene = None;
}

fn reload<P: Html5Parser<C, Document = D>>(&mut self, mut el: impl WindowedEventLoop<B, RenderTree<L, C>, C>) {
let fetcher = self.fetcher.clone();

gosub_shared::async_executor::spawn(async move {
info!("Reloading tab");

let rt = match load_html_rendertree_fetcher::<L, P, C>(fetcher.base().clone(), &fetcher).await {
Ok(rt) => rt,
Err(e) => {
error!("Failed to reload tab: {e}");
return;
}
};

el.reload_from(rt);
})
}

fn reload_from(&mut self, tree: RenderTree<L, C>) {
self.tree = tree;
self.size = None;
self.position = PositionTree::default();
self.last_hover = None;
self.debugger_scene = None;
self.dirty = false;
self.tree_scene = None;
self.selected_element = None;
self.scene_transform = None;
}
}

struct Drawer<'s, 't, B: RenderBackend, L: Layouter, D: Document<C>, C: CssSystem, EL: WindowedEventLoop<B>> {
struct Drawer<
's,
't,
B: RenderBackend,
L: Layouter,
D: Document<C>,
C: CssSystem,
EL: WindowedEventLoop<B, RT, C>,
RT: render_tree::RenderTree<C>,
> {
scene: &'s mut B::Scene,
drawer: &'t mut TreeDrawer<B, L, D, C>,
svg: Arc<Mutex<B::SVGRenderer>>,
el: &'t EL,
_marker: PhantomData<fn(RT)>,
}

impl<B: RenderBackend, L: Layouter, D: Document<C>, C: CssSystem, EL: WindowedEventLoop<B>>
Drawer<'_, '_, B, L, D, C, EL>
impl<
B: RenderBackend,
L: Layouter,
D: Document<C>,
C: CssSystem,
EL: WindowedEventLoop<B, RT, C>,
RT: render_tree::RenderTree<C>,
> Drawer<'_, '_, B, L, D, C, EL, RT>
where
<<B as RenderBackend>::Text as Text>::Font: From<<<L as Layouter>::TextLayout as TextLayout>::Font>,
{
Expand Down Expand Up @@ -316,7 +375,7 @@ where
pos.x += p.x as FP;
pos.y += p.y as FP;

let (border_radius, new_size) = render_bg::<B, L, C>(
let (border_radius, new_size) = render_bg::<B, L, C, RT>(
node,
self.scene,
pos,
Expand All @@ -336,7 +395,7 @@ where

let size = node.layout.size_or().map(|x| x.u32());

let img = request_img::<B>(
let img = request_img::<B, RT, C>(
self.drawer.fetcher.clone(),
self.svg.clone(),
url,
Expand Down Expand Up @@ -570,14 +629,14 @@ pub fn print_tree<B: RenderBackend, L: Layouter>(
}
*/

fn render_bg<B: RenderBackend, L: Layouter, C: CssSystem>(
fn render_bg<B: RenderBackend, L: Layouter, C: CssSystem, RT: render_tree::RenderTree<C>>(
node: &RenderTreeNode<L, C>,
scene: &mut B::Scene,
pos: &Point,
svg: Arc<Mutex<B::SVGRenderer>>,
fetcher: Arc<Fetcher>,
img_cache: &mut ImageCache<B>,
el: &impl WindowedEventLoop<B>,
el: &impl WindowedEventLoop<B, RT, C>,
) -> ((FP, FP, FP, FP), Option<SizeU32>) {
let bg_color = node
.properties
Expand Down Expand Up @@ -660,7 +719,7 @@ fn render_bg<B: RenderBackend, L: Layouter, C: CssSystem>(
if let Some(url) = background_image {
let size = node.layout.size_or().map(|x| x.u32());

let img = match request_img::<B>(fetcher.clone(), svg.clone(), url, size, img_cache, el) {
let img = match request_img::<B, RT, C>(fetcher.clone(), svg.clone(), url, size, img_cache, el) {
Ok(img) => img,
Err(e) => {
eprintln!("Error loading image: {:?}", e);
Expand Down
6 changes: 4 additions & 2 deletions crates/gosub_renderer/src/draw/img.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,17 @@ use gosub_render_backend::svg::SvgRenderer;
use gosub_render_backend::{
Image as _, ImageBuffer, ImageCacheEntry, ImgCache, RenderBackend, SizeU32, WindowedEventLoop,
};
use gosub_shared::traits::css3::CssSystem;
use gosub_shared::traits::render_tree::RenderTree;
use gosub_shared::types::Result;

pub fn request_img<B: RenderBackend>(
pub fn request_img<B: RenderBackend, RT: RenderTree<C>, C: CssSystem>(
fetcher: Arc<Fetcher>,
svg_renderer: Arc<Mutex<B::SVGRenderer>>,
url: &str,
size: Option<SizeU32>,
img_cache: &mut ImageCache<B>,
el: &impl WindowedEventLoop<B>,
el: &impl WindowedEventLoop<B, RT, C>,
) -> Result<ImageBuffer<B>> {
let img = img_cache.get(url);

Expand Down
12 changes: 11 additions & 1 deletion crates/gosub_renderer/src/render_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,16 @@ pub(crate) async fn load_html_rendertree<L: Layouter, P: Html5Parser<C>, C: CssS
url: Url,
) -> gosub_shared::types::Result<(RenderTree<L, C>, Fetcher)> {
let fetcher = Fetcher::new(url.clone());

let rt = load_html_rendertree_fetcher::<L, P, C>(url, &fetcher).await?;

Ok((rt, fetcher))
}

pub(crate) async fn load_html_rendertree_fetcher<L: Layouter, P: Html5Parser<C>, C: CssSystem>(
url: Url,
fetcher: &Fetcher,
) -> gosub_shared::types::Result<RenderTree<L, C>> {
let html = if url.scheme() == "http" || url.scheme() == "https" {
// Fetch the html from the url
let response = fetcher.get(url.as_ref()).await?;
Expand Down Expand Up @@ -101,5 +111,5 @@ pub(crate) async fn load_html_rendertree<L: Layouter, P: Html5Parser<C>, C: CssS

drop(doc);

Ok((generate_render_tree(DocumentHandle::clone(&doc_handle))?, fetcher))
generate_render_tree(DocumentHandle::clone(&doc_handle))
}
2 changes: 1 addition & 1 deletion crates/gosub_shared/src/traits/render_tree.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::traits::css3::CssSystem;

pub trait RenderTree<C: CssSystem> {
pub trait RenderTree<C: CssSystem>: Send + 'static {
type NodeId: Copy;

type Node: RenderTreeNode<C>;
Expand Down
Loading

0 comments on commit 8a01d75

Please sign in to comment.