From 250026f7f69d47de2120c8a7c99441f168c15b84 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Thu, 15 Feb 2024 00:05:29 +0100 Subject: [PATCH] render: fix top-left clipping of surfaces --- src/cursor.rs | 29 +---- src/gfx_api.rs | 6 +- src/ifs/wl_surface.rs | 11 +- src/ifs/wl_surface/cursor.rs | 26 +--- src/ifs/wl_surface/x_surface/xwindow.rs | 11 +- src/ifs/wl_surface/xdg_surface/xdg_popup.rs | 11 +- .../wl_surface/xdg_surface/xdg_toplevel.rs | 11 +- src/ifs/wl_surface/zwlr_layer_surface_v1.rs | 9 +- src/portal/ptr_gui.rs | 6 +- src/renderer.rs | 121 ++++++------------ src/renderer/renderer_base.rs | 117 +++++++++++------ src/tree.rs | 12 +- src/tree/container.rs | 9 +- src/tree/display.rs | 9 +- src/tree/float.rs | 9 +- src/tree/output.rs | 9 +- src/tree/placeholder.rs | 9 +- src/tree/workspace.rs | 9 +- 18 files changed, 147 insertions(+), 277 deletions(-) diff --git a/src/cursor.rs b/src/cursor.rs index a5ca594c..7aeb711f 100644 --- a/src/cursor.rs +++ b/src/cursor.rs @@ -366,8 +366,7 @@ fn render_img(image: &InstantiatedCursorImage, renderer: &mut Renderer, x: Fixed None, None, scale, - i32::MAX, - i32::MAX, + None, ); } } @@ -379,16 +378,9 @@ impl Cursor for StaticCursor { fn render_hardware_cursor(&self, renderer: &mut Renderer) { if let Some(img) = self.image.scales.get(&renderer.scale()) { - renderer.base.render_texture( - &img.tex, - 0, - 0, - None, - None, - renderer.scale(), - i32::MAX, - i32::MAX, - ); + renderer + .base + .render_texture(&img.tex, 0, 0, None, None, renderer.scale(), None); } } @@ -416,16 +408,9 @@ impl Cursor for AnimatedCursor { fn render_hardware_cursor(&self, renderer: &mut Renderer) { let img = &self.images[self.idx.get()]; if let Some(img) = img.scales.get(&renderer.scale()) { - renderer.base.render_texture( - &img.tex, - 0, - 0, - None, - None, - renderer.scale(), - i32::MAX, - i32::MAX, - ); + renderer + .base + .render_texture(&img.tex, 0, 0, None, None, renderer.scale(), None); } } diff --git a/src/gfx_api.rs b/src/gfx_api.rs index 36c28f01..38fa1674 100644 --- a/src/gfx_api.rs +++ b/src/gfx_api.rs @@ -150,7 +150,7 @@ impl dyn GfxFramebuffer { scale, scalef: 1.0, }; - renderer.render_texture(texture, x, y, None, None, scale, i32::MAX, i32::MAX); + renderer.render_texture(texture, x, y, None, None, scale, None); let clear = self.format().has_alpha.then_some(&Color::TRANSPARENT); self.render(ops, clear); } @@ -195,7 +195,7 @@ impl dyn GfxFramebuffer { logical_extents: node.node_absolute_position().at_point(0, 0), physical_extents: Rect::new(0, 0, width, height).unwrap(), }; - node.node_render(&mut renderer, 0, 0, i32::MAX, i32::MAX); + node.node_render(&mut renderer, 0, 0, None); if let Some(rect) = cursor_rect { let seats = state.globals.lock_seats(); for seat in seats.values() { @@ -208,7 +208,7 @@ impl dyn GfxFramebuffer { ); if extents.intersects(&rect) { let (x, y) = rect.translate(extents.x1(), extents.y1()); - renderer.render_surface(&dnd_icon, x, y, i32::MAX, i32::MAX); + renderer.render_surface(&dnd_icon, x, y, None); } } if render_hardware_cursor || !seat.hardware_cursor() { diff --git a/src/ifs/wl_surface.rs b/src/ifs/wl_surface.rs index 18b4c6c4..7f0c6cd8 100644 --- a/src/ifs/wl_surface.rs +++ b/src/ifs/wl_surface.rs @@ -1142,15 +1142,8 @@ impl Node for WlSurface { } } - fn node_render( - &self, - renderer: &mut Renderer, - x: i32, - y: i32, - max_width: i32, - max_height: i32, - ) { - renderer.render_surface(self, x, y, max_width, max_height); + fn node_render(&self, renderer: &mut Renderer, x: i32, y: i32, bounds: Option<&Rect>) { + renderer.render_surface(self, x, y, bounds); } fn node_client(&self) -> Option> { diff --git a/src/ifs/wl_surface/cursor.rs b/src/ifs/wl_surface/cursor.rs index 78709a38..79580eff 100644 --- a/src/ifs/wl_surface/cursor.rs +++ b/src/ifs/wl_surface/cursor.rs @@ -76,36 +76,16 @@ impl Cursor for CursorSurface { let (hot_x, hot_y) = (Fixed::from_int(hot_x), Fixed::from_int(hot_y)); let x = ((x - hot_x).to_f64() * scale).round() as _; let y = ((y - hot_y).to_f64() * scale).round() as _; - renderer.render_surface_scaled( - &self.surface, - x, - y, - None, - i32::MAX, - i32::MAX, - false, - ); + renderer.render_surface_scaled(&self.surface, x, y, None, None, false); } else { - renderer.render_surface( - &self.surface, - x_int - hot_x, - y_int - hot_y, - i32::MAX, - i32::MAX, - ); + renderer.render_surface(&self.surface, x_int - hot_x, y_int - hot_y, None); } } } fn render_hardware_cursor(&self, renderer: &mut Renderer) { let extents = self.surface.extents.get(); - renderer.render_surface( - &self.surface, - -extents.x1(), - -extents.y1(), - i32::MAX, - i32::MAX, - ); + renderer.render_surface(&self.surface, -extents.x1(), -extents.y1(), None); struct FrameRequests; impl NodeVisitorBase for FrameRequests { diff --git a/src/ifs/wl_surface/x_surface/xwindow.rs b/src/ifs/wl_surface/x_surface/xwindow.rs index b13f044b..e7aecde0 100644 --- a/src/ifs/wl_surface/x_surface/xwindow.rs +++ b/src/ifs/wl_surface/x_surface/xwindow.rs @@ -332,15 +332,8 @@ impl Node for Xwindow { FindTreeResult::Other } - fn node_render( - &self, - renderer: &mut Renderer, - x: i32, - y: i32, - max_width: i32, - max_height: i32, - ) { - renderer.render_surface(&self.x.surface, x, y, max_width, max_height) + fn node_render(&self, renderer: &mut Renderer, x: i32, y: i32, bounds: Option<&Rect>) { + renderer.render_surface(&self.x.surface, x, y, bounds) } fn node_client(&self) -> Option> { diff --git a/src/ifs/wl_surface/xdg_surface/xdg_popup.rs b/src/ifs/wl_surface/xdg_surface/xdg_popup.rs index 58d19d4c..39f8ce4b 100644 --- a/src/ifs/wl_surface/xdg_surface/xdg_popup.rs +++ b/src/ifs/wl_surface/xdg_surface/xdg_popup.rs @@ -300,15 +300,8 @@ impl Node for XdgPopup { self.xdg.find_tree_at(x, y, tree) } - fn node_render( - &self, - renderer: &mut Renderer, - x: i32, - y: i32, - max_width: i32, - max_height: i32, - ) { - renderer.render_xdg_surface(&self.xdg, x, y, max_width, max_height) + fn node_render(&self, renderer: &mut Renderer, x: i32, y: i32, bounds: Option<&Rect>) { + renderer.render_xdg_surface(&self.xdg, x, y, bounds) } fn node_client(&self) -> Option> { diff --git a/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs b/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs index eee6daea..564cf487 100644 --- a/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs +++ b/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs @@ -422,15 +422,8 @@ impl Node for XdgToplevel { self.xdg.find_tree_at(x, y, tree) } - fn node_render( - &self, - renderer: &mut Renderer, - x: i32, - y: i32, - max_width: i32, - max_height: i32, - ) { - renderer.render_xdg_surface(&self.xdg, x, y, max_width, max_height) + fn node_render(&self, renderer: &mut Renderer, x: i32, y: i32, bounds: Option<&Rect>) { + renderer.render_xdg_surface(&self.xdg, x, y, bounds) } fn node_client(&self) -> Option> { diff --git a/src/ifs/wl_surface/zwlr_layer_surface_v1.rs b/src/ifs/wl_surface/zwlr_layer_surface_v1.rs index 0cc368a0..b6d9efcd 100644 --- a/src/ifs/wl_surface/zwlr_layer_surface_v1.rs +++ b/src/ifs/wl_surface/zwlr_layer_surface_v1.rs @@ -394,14 +394,7 @@ impl Node for ZwlrLayerSurfaceV1 { self.surface.find_tree_at_(x, y, tree) } - fn node_render( - &self, - renderer: &mut Renderer, - x: i32, - y: i32, - _max_width: i32, - _max_height: i32, - ) { + fn node_render(&self, renderer: &mut Renderer, x: i32, y: i32, _bounds: Option<&Rect>) { renderer.render_layer_surface(self, x, y); } } diff --git a/src/portal/ptr_gui.rs b/src/portal/ptr_gui.rs index eb99eac9..93276069 100644 --- a/src/portal/ptr_gui.rs +++ b/src/portal/ptr_gui.rs @@ -221,8 +221,7 @@ impl GuiElement for Button { None, None, r.scale(), - i32::MAX, - i32::MAX, + None, ); } } @@ -323,8 +322,7 @@ impl GuiElement for Label { None, None, r.scale(), - i32::MAX, - i32::MAX, + None, ); } } diff --git a/src/renderer.rs b/src/renderer.rs index 35864769..7d1901d8 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -76,7 +76,7 @@ impl Renderer<'_> { if self.state.lock.locked.get() { if let Some(surface) = output.lock_surface.get() { if surface.surface.buffer.get().is_some() { - self.render_surface(&surface.surface, x, y, i32::MAX, i32::MAX); + self.render_surface(&surface.surface, x, y, None); } } return; @@ -97,7 +97,7 @@ impl Renderer<'_> { } if let Some(ws) = output.workspace.get() { if let Some(fs) = ws.fullscreen.get() { - fs.tl_as_node().node_render(self, x, y, i32::MAX, i32::MAX); + fs.tl_as_node().node_render(self, x, y, None); render_layer!(output.layers[2]); render_layer!(output.layers[3]); return; @@ -143,20 +143,12 @@ impl Renderer<'_> { for title in &rd.titles { let (x, y) = self.base.scale_point(x + title.tex_x, y + title.tex_y); self.base - .render_texture(&title.tex, x, y, None, None, scale, i32::MAX, i32::MAX); + .render_texture(&title.tex, x, y, None, None, scale, None); } if let Some(status) = &rd.status { let (x, y) = self.base.scale_point(x + status.tex_x, y + status.tex_y); - self.base.render_texture( - &status.tex.texture, - x, - y, - None, - None, - scale, - i32::MAX, - i32::MAX, - ); + self.base + .render_texture(&status.tex.texture, x, y, None, None, scale, None); } } if let Some(ws) = output.workspace.get() { @@ -168,7 +160,7 @@ impl Renderer<'_> { let pos = stacked.node_absolute_position(); if pos.intersects(&opos) { let (x, y) = opos.translate(pos.x1(), pos.y1()); - stacked.node_render(self, x, y, i32::MAX, i32::MAX); + stacked.node_render(self, x, y, None); } } } @@ -192,16 +184,8 @@ impl Renderer<'_> { let (tex_width, tex_height) = tex.texture.size(); let x = x + (pos.width() - tex_width) / 2; let y = y + (pos.height() - tex_height) / 2; - self.base.render_texture( - &tex.texture, - x, - y, - None, - None, - self.base.scale, - i32::MAX, - i32::MAX, - ); + self.base + .render_texture(&tex.texture, x, y, None, None, self.base.scale, None); } } @@ -237,8 +221,7 @@ impl Renderer<'_> { None, None, self.base.scale, - i32::MAX, - i32::MAX, + None, ); } } @@ -247,13 +230,9 @@ impl Renderer<'_> { let body = container.mono_body.get().move_(x, y); let body = self.base.scale_rect(body); let content = container.mono_content.get(); - child.node.node_render( - self, - x + content.x1(), - y + content.y1(), - body.width(), - body.height(), - ); + child + .node + .node_render(self, x + content.x1(), y + content.y1(), Some(&body)); } else { for child in container.children.iter() { let body = child.body.get(); @@ -263,13 +242,9 @@ impl Renderer<'_> { let body = body.move_(x, y); let body = self.base.scale_rect(body); let content = child.content.get(); - child.node.node_render( - self, - x + content.x1(), - y + content.y1(), - body.width(), - body.height(), - ); + child + .node + .node_render(self, x + content.x1(), y + content.y1(), Some(&body)); } } } @@ -279,8 +254,7 @@ impl Renderer<'_> { xdg: &XdgSurface, mut x: i32, mut y: i32, - max_width: i32, - max_height: i32, + bounds: Option<&Rect>, ) { let surface = &xdg.surface; if let Some(geo) = xdg.geometry() { @@ -288,19 +262,12 @@ impl Renderer<'_> { x = xt; y = yt; } - self.render_surface(surface, x, y, max_width, max_height); + self.render_surface(surface, x, y, bounds); } - pub fn render_surface( - &mut self, - surface: &WlSurface, - x: i32, - y: i32, - max_width: i32, - max_height: i32, - ) { + pub fn render_surface(&mut self, surface: &WlSurface, x: i32, y: i32, bounds: Option<&Rect>) { let (x, y) = self.base.scale_point(x, y); - self.render_surface_scaled(surface, x, y, None, max_width, max_height, false); + self.render_surface_scaled(surface, x, y, None, bounds, false); } pub fn render_surface_scaled( @@ -309,8 +276,7 @@ impl Renderer<'_> { x: i32, y: i32, pos_rel: Option<(i32, i32)>, - max_width: i32, - max_height: i32, + bounds: Option<&Rect>, is_subsurface: bool, ) { let children = surface.children.borrow(); @@ -346,18 +312,17 @@ impl Renderer<'_> { x + x1, y + y1, Some((pos.x1(), pos.y1())), - max_width, - max_height, + bounds, true, ); } }; } render!(&children.below); - self.render_buffer(&buffer, x, y, *tpoints, size, max_width, max_height); + self.render_buffer(&buffer, x, y, *tpoints, size, bounds); render!(&children.above); } else { - self.render_buffer(&buffer, x, y, *tpoints, size, max_width, max_height); + self.render_buffer(&buffer, x, y, *tpoints, size, bounds); } if let Some(result) = self.result.as_deref_mut() { { @@ -378,8 +343,7 @@ impl Renderer<'_> { y: i32, tpoints: BufferPoints, tsize: (i32, i32), - max_width: i32, - max_height: i32, + bounds: Option<&Rect>, ) { if let Some(tex) = buffer.texture.get() { self.base.render_texture( @@ -389,14 +353,17 @@ impl Renderer<'_> { Some(tpoints), Some(tsize), self.base.scale, - max_width, - max_height, + bounds, ); } else if let Some(color) = &buffer.color { - if let Some(rect) = - Rect::new_sized(x, y, tsize.0.min(max_width), tsize.1.min(max_height)) - { - self.base.fill_boxes(&[rect], color); + if let Some(rect) = Rect::new_sized(x, y, tsize.0, tsize.1) { + let rect = match bounds { + None => rect, + Some(bounds) => rect.intersect(*bounds), + }; + if !rect.is_empty() { + self.base.fill_boxes(&[rect], color); + } } } else { log::info!("live buffer has neither a texture nor is a single-pixel buffer"); @@ -435,16 +402,8 @@ impl Renderer<'_> { self.base.fill_boxes(&title_underline, &uc); if let Some(title) = floating.title_textures.get(&self.base.scale) { let (x, y) = self.base.scale_point(x + bw, y + bw); - self.base.render_texture( - &title.texture, - x, - y, - None, - None, - self.base.scale, - i32::MAX, - i32::MAX, - ); + self.base + .render_texture(&title.texture, x, y, None, None, self.base.scale, None); } let body = Rect::new_sized( x + bw, @@ -454,18 +413,12 @@ impl Renderer<'_> { ) .unwrap(); let scissor_body = self.base.scale_rect(body); - child.node_render( - self, - body.x1(), - body.y1(), - scissor_body.width(), - scissor_body.height(), - ); + child.node_render(self, body.x1(), body.y1(), Some(&scissor_body)); } pub fn render_layer_surface(&mut self, surface: &ZwlrLayerSurfaceV1, x: i32, y: i32) { let body = surface.position().at_point(x, y); let body = self.base.scale_rect(body); - self.render_surface(&surface.surface, x, y, body.width(), body.height()); + self.render_surface(&surface.surface, x, y, Some(&body)); } } diff --git a/src/renderer/renderer_base.rs b/src/renderer/renderer_base.rs index 5ee35e8d..4cca752f 100644 --- a/src/renderer/renderer_base.rs +++ b/src/renderer/renderer_base.rs @@ -120,8 +120,7 @@ impl RendererBase<'_> { tpoints: Option, tsize: Option<(i32, i32)>, tscale: Scale, - max_width: i32, - max_height: i32, + bounds: Option<&Rect>, ) { let mut texcoord = tpoints.unwrap_or(BufferPoints { top_left: BufferPoint { x: 0.0, y: 0.0 }, @@ -142,49 +141,89 @@ impl RendererBase<'_> { (w, h) }; - macro_rules! clamp { - ($desired:ident, $max:ident, $([$far:ident, $near:ident]),*) => { - if $desired > $max { - let $desired = $desired as f32; - let $max = $max as f32; - let factor = $max / $desired; - $( - let dx = (texcoord.$far.x - texcoord.$near.x) * factor; - texcoord.$far.x = texcoord.$near.x + dx; - let dy = (texcoord.$far.y - texcoord.$near.y) * factor; - texcoord.$far.y = texcoord.$near.y + dy; - )* - $max - } else { - $desired as f32 - } - }; - } + let mut target_x = [x, x + twidth]; + let mut target_y = [y, y + theight]; + + if let Some(bounds) = bounds { + #[cold] + fn cold() {} + + let bounds_x = [bounds.x1(), bounds.x2()]; + let bounds_y = [bounds.y1(), bounds.y2()]; + + macro_rules! clamp { + ($desired:ident, $bounds:ident, $test_idx:expr, $test_cmp:ident, $test_cmp_eq:ident, $([$modify:ident, $keep:ident],)*) => {{ + let desired_test = $desired[$test_idx]; + let desired_other = $desired[1 - $test_idx]; + let bound = $bounds[$test_idx]; + if desired_test.$test_cmp(&bound) { + cold(); + if desired_other.$test_cmp_eq(&bound) { + return; + } + let max = (desired_other - bound) as f32; + let desired = ($desired[1] - $desired[0]) as f32; + let factor = max.abs() / desired; + $( + let dx = (texcoord.$modify.x - texcoord.$keep.x) * factor; + texcoord.$modify.x = texcoord.$keep.x + dx; + let dy = (texcoord.$modify.y - texcoord.$keep.y) * factor; + texcoord.$modify.y = texcoord.$keep.y + dy; + )* + $desired[$test_idx] = bound; + } + }}; + } - let twidth = clamp!( - twidth, - max_width, - [top_right, top_left], - [bottom_right, bottom_left] - ); - let theight = clamp!( - theight, - max_height, - [bottom_left, top_left], - [bottom_right, top_right] - ); - - let x = x as f32; - let y = y as f32; + clamp!( + target_x, + bounds_x, + 0, + lt, + le, + [top_left, top_right], + [bottom_left, bottom_right], + ); + + clamp!( + target_x, + bounds_x, + 1, + gt, + ge, + [top_right, top_left], + [bottom_right, bottom_left], + ); + + clamp!( + target_y, + bounds_y, + 0, + lt, + le, + [top_left, bottom_left], + [top_right, bottom_right], + ); + + clamp!( + target_y, + bounds_y, + 1, + gt, + ge, + [bottom_left, top_left], + [bottom_right, top_right], + ); + } self.ops.push(GfxApiOpt::CopyTexture(CopyTexture { tex: texture.clone(), source: texcoord, target: AbsoluteRect { - x1: x, - y1: y, - x2: x + twidth, - y2: y + theight, + x1: target_x[0] as f32, + y1: target_y[0] as f32, + x2: target_x[1] as f32, + y2: target_y[1] as f32, }, })); } diff --git a/src/tree.rs b/src/tree.rs index 0ea96811..a652e1a7 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -137,19 +137,11 @@ pub trait Node: 'static { let _ = (child, active, depth); } - fn node_render( - &self, - renderer: &mut Renderer, - x: i32, - y: i32, - max_width: i32, - max_height: i32, - ) { + fn node_render(&self, renderer: &mut Renderer, x: i32, y: i32, bounds: Option<&Rect>) { let _ = renderer; let _ = x; let _ = y; - let _ = max_width; - let _ = max_height; + let _ = bounds; } fn node_client(&self) -> Option> { diff --git a/src/tree/container.rs b/src/tree/container.rs index 21206d20..665a029e 100644 --- a/src/tree/container.rs +++ b/src/tree/container.rs @@ -1140,14 +1140,7 @@ impl Node for ContainerNode { .node_child_active_changed(self.deref(), active, depth + 1); } - fn node_render( - &self, - renderer: &mut Renderer, - x: i32, - y: i32, - _max_width: i32, - _max_height: i32, - ) { + fn node_render(&self, renderer: &mut Renderer, x: i32, y: i32, _bounds: Option<&Rect>) { renderer.render_container(self, x, y); } diff --git a/src/tree/display.rs b/src/tree/display.rs index a60ca10f..caad562f 100644 --- a/src/tree/display.rs +++ b/src/tree/display.rs @@ -111,14 +111,7 @@ impl Node for DisplayNode { FindTreeResult::AcceptsInput } - fn node_render( - &self, - renderer: &mut Renderer, - x: i32, - y: i32, - _max_width: i32, - _max_height: i32, - ) { + fn node_render(&self, renderer: &mut Renderer, x: i32, y: i32, _bounds: Option<&Rect>) { renderer.render_display(self, x, y); } diff --git a/src/tree/float.rs b/src/tree/float.rs index 62f6eeae..457ac09c 100644 --- a/src/tree/float.rs +++ b/src/tree/float.rs @@ -446,14 +446,7 @@ impl Node for FloatNode { } } - fn node_render( - &self, - renderer: &mut Renderer, - x: i32, - y: i32, - _max_width: i32, - _max_height: i32, - ) { + fn node_render(&self, renderer: &mut Renderer, x: i32, y: i32, _bounds: Option<&Rect>) { renderer.render_floating(self, x, y) } diff --git a/src/tree/output.rs b/src/tree/output.rs index f66a1bd2..750e33bd 100644 --- a/src/tree/output.rs +++ b/src/tree/output.rs @@ -636,14 +636,7 @@ impl Node for OutputNode { FindTreeResult::AcceptsInput } - fn node_render( - &self, - renderer: &mut Renderer, - x: i32, - y: i32, - _max_width: i32, - _max_height: i32, - ) { + fn node_render(&self, renderer: &mut Renderer, x: i32, y: i32, _bounds: Option<&Rect>) { renderer.render_output(self, x, y); } diff --git a/src/tree/placeholder.rs b/src/tree/placeholder.rs index c5bdcceb..60242468 100644 --- a/src/tree/placeholder.rs +++ b/src/tree/placeholder.rs @@ -123,14 +123,7 @@ impl Node for PlaceholderNode { FindTreeResult::AcceptsInput } - fn node_render( - &self, - renderer: &mut Renderer, - x: i32, - y: i32, - _max_width: i32, - _max_height: i32, - ) { + fn node_render(&self, renderer: &mut Renderer, x: i32, y: i32, _bounds: Option<&Rect>) { renderer.render_placeholder(self, x, y); } diff --git a/src/tree/workspace.rs b/src/tree/workspace.rs index 0e068aa2..81564c20 100644 --- a/src/tree/workspace.rs +++ b/src/tree/workspace.rs @@ -224,14 +224,7 @@ impl Node for WorkspaceNode { FindTreeResult::AcceptsInput } - fn node_render( - &self, - renderer: &mut Renderer, - x: i32, - y: i32, - _max_width: i32, - _max_height: i32, - ) { + fn node_render(&self, renderer: &mut Renderer, x: i32, y: i32, _bounds: Option<&Rect>) { renderer.render_workspace(self, x, y); }