Merge branch 'render-refactor' of github.com:osui-rs/osui into render-refactor

This commit is contained in:
2025-08-08 23:38:21 +02:00
6 changed files with 143 additions and 160 deletions
+22 -30
View File
@@ -1,10 +1,14 @@
use std::sync::Arc;
use crate::{
prelude::ElementRenderer,
style::RawTransform,
widget::{Element, Widget},
NoRender, NoRenderRoot,
NoRenderRoot,
};
pub struct DivRenderer<'a>(pub &'a mut RawTransform);
pub struct Div {
children: Vec<Arc<Widget>>,
size: (u16, u16),
@@ -35,39 +39,17 @@ impl Element for Div {
ctx: &crate::extensions::Context,
) {
let mut transform = scope.get_transform().clone();
let mut renderer = DivRenderer(&mut transform);
let (w, h) = scope.get_parent_size();
scope.set_parent_size(transform.width, transform.height);
scope.set_parent_size(renderer.0.width, renderer.0.height);
for elem in &self.children {
if elem.get::<NoRender>().is_some() {
continue;
}
scope.clear();
if let Some(style) = elem.get() {
scope.set_style(style);
}
if let Some(t) = elem.get() {
scope.set_transform(&t);
}
elem.get_elem().render(scope, ctx);
ctx.render(elem, scope);
if let Some(t) = elem.get() {
scope.set_transform(&t);
}
let t = scope.get_transform_mut();
transform.width = transform.width.max(t.x + t.width + (t.px * 2));
transform.height = transform.height.max(t.y + t.height + (t.py * 2));
t.x += transform.x + transform.px;
t.y += transform.y + transform.py;
scope.draw();
elem.get_elem().after_render(scope, ctx);
ctx.after_render(elem, scope);
for widget in &self.children {
scope.render_widget(&mut renderer, ctx, widget);
}
scope.set_parent_size(w, h);
self.size = (transform.width, transform.height);
self.size = (renderer.0.width, renderer.0.height);
}
fn draw_child(&mut self, element: &Arc<Widget>) {
@@ -83,3 +65,13 @@ impl Element for Div {
self
}
}
impl ElementRenderer for DivRenderer<'_> {
fn before_draw(&mut self, scope: &mut crate::prelude::RenderScope, _widget: &Arc<Widget>) {
let t = scope.get_transform_mut();
self.0.width = self.0.width.max(t.width + (t.px * 2));
self.0.height = self.0.height.max(t.height + (t.py * 2));
t.x += self.0.x + self.0.px;
t.y += self.0.y + self.0.py;
}
}
+43 -62
View File
@@ -1,10 +1,15 @@
use std::sync::Arc;
use crate::{
prelude::ElementRenderer,
style::RawTransform,
widget::{Element, Widget},
NoRender, NoRenderRoot,
NoRenderRoot,
};
pub struct RowRenderer<'a>(&'a mut RawTransform, u16, &'a mut u16);
pub struct ColumnRenderer<'a>(&'a mut RawTransform, u16, &'a mut u16);
pub struct FlexRow {
pub gap: u16,
children: Vec<Arc<Widget>>,
@@ -56,43 +61,16 @@ impl Element for FlexRow {
let transform_before = transform.clone();
let (w, h) = scope.get_parent_size();
scope.set_parent_size(transform.width, transform.height);
let mut v = 0;
for elem in &self.children {
if elem.get::<NoRender>().is_some() {
continue;
}
let mut renderer = RowRenderer(&mut transform, self.gap, &mut v);
scope.clear();
if let Some(style) = elem.get() {
scope.set_style(style);
}
if let Some(t) = elem.get() {
scope.set_transform(&t);
}
elem.get_elem().render(scope, ctx);
ctx.render(elem, scope);
if let Some(t) = elem.get() {
scope.set_transform(&t);
}
let t = scope.get_transform_mut();
transform.width = transform.width.max(t.width);
transform.height = transform.height.max(v + t.height);
t.x += transform.x;
t.y += transform.y + v;
v += t.height + self.gap + (t.py * 2);
t.px += transform.px;
t.py += transform.py;
scope.draw();
elem.get_elem().after_render(scope, ctx);
ctx.after_render(elem, scope);
for widget in &self.children {
scope.render_widget(&mut renderer, ctx, widget);
}
scope.set_parent_size(w, h);
self.size = (transform.width, transform.height);
scope.set_transform_raw(transform_before);
self.size = (transform.width, transform.height);
}
fn draw_child(&mut self, element: &Arc<Widget>) {
@@ -128,39 +106,12 @@ impl Element for FlexCol {
let transform_before = transform.clone();
let (w, h) = scope.get_parent_size();
scope.set_parent_size(transform.width, transform.height);
let mut v = 0;
for elem in &self.children {
if elem.get::<NoRender>().is_some() {
continue;
}
let mut renderer = ColumnRenderer(&mut transform, self.gap, &mut v);
scope.clear();
if let Some(style) = elem.get() {
scope.set_style(style);
}
if let Some(t) = elem.get() {
scope.set_transform(&t);
}
elem.get_elem().render(scope, ctx);
ctx.render(elem, scope);
if let Some(t) = elem.get() {
scope.set_transform(&t);
}
let t = scope.get_transform_mut();
transform.width = transform.width.max(v + t.width + (t.px * 2));
transform.height = transform.height.max(t.height + (t.py * 2));
t.x += transform.x + v;
t.y += transform.y;
v += t.width + self.gap + (t.px * 2);
t.px += transform.px;
t.py += transform.py;
scope.draw();
elem.get_elem().after_render(scope, ctx);
ctx.after_render(elem, scope);
for widget in &self.children {
scope.render_widget(&mut renderer, ctx, widget);
}
scope.set_parent_size(w, h);
scope.set_transform_raw(transform_before);
@@ -180,3 +131,33 @@ impl Element for FlexCol {
self
}
}
impl ElementRenderer for RowRenderer<'_> {
fn before_draw(&mut self, scope: &mut crate::prelude::RenderScope, _widget: &Arc<Widget>) {
let t = scope.get_transform_mut();
self.0.width = self.0.width.max(*self.2 + t.width + (t.px * 2));
self.0.height = self.0.height.max(t.height + (t.py * 2));
t.x += self.0.x;
t.y += self.0.y + *self.2;
*self.2 += t.height + self.1 + (t.py * 2);
t.px += self.0.px;
t.py += self.0.py;
}
}
impl ElementRenderer for ColumnRenderer<'_> {
fn before_draw(&mut self, scope: &mut crate::prelude::RenderScope, _widget: &Arc<Widget>) {
let t = scope.get_transform_mut();
self.0.width = self.0.width.max(*self.2 + t.width + (t.px * 2));
self.0.height = self.0.height.max(t.height + (t.py * 2));
t.x += self.0.x + *self.2;
t.y += self.0.y;
*self.2 += t.width + self.1 + (t.px * 2);
t.px += self.0.px;
t.py += self.0.py;
}
}
+7 -28
View File
@@ -3,8 +3,9 @@ use std::sync::Arc;
use crossterm::event::{KeyCode, KeyEvent};
use crate::{
prelude::DivRenderer,
widget::{Element, Widget},
NoRender, NoRenderRoot,
NoRenderRoot,
};
pub struct Paginator {
@@ -38,38 +39,16 @@ impl Element for Paginator {
scope: &mut crate::render_scope::RenderScope,
ctx: &crate::extensions::Context,
) {
if let Some(elem) = self.children.get(self.index) {
if elem.get::<NoRender>().is_some() {
return;
}
if let Some(widget) = self.children.get(self.index) {
let mut transform = scope.get_transform().clone();
let mut renderer = DivRenderer(&mut transform);
let (w, h) = scope.get_parent_size();
scope.set_parent_size(transform.width, transform.height);
scope.clear();
scope.set_parent_size(renderer.0.width, renderer.0.height);
if let Some(style) = elem.get() {
scope.set_style(style);
}
if let Some(t) = elem.get() {
scope.set_transform(&t);
}
elem.get_elem().render(scope, ctx);
if let Some(t) = elem.get() {
scope.set_transform(&t);
}
let t = scope.get_transform_mut();
transform.width = transform.width.max(t.x + t.width + (t.px * 2));
transform.height = transform.height.max(t.y + t.height + (t.py * 2));
t.x += transform.x + transform.px;
t.y += transform.y + transform.py;
scope.draw();
elem.get_elem().after_render(scope, ctx);
ctx.after_render(elem, scope);
scope.render_widget(&mut renderer, ctx, widget);
scope.set_parent_size(w, h);
self.size = (transform.width, transform.height);
self.size = (renderer.0.width, renderer.0.height);
}
}
+6
View File
@@ -119,6 +119,12 @@ impl Context {
components
}
pub fn render_root(&self, scope: &mut RenderScope) {
for ext in self.screen.extensions.lock().unwrap().iter() {
ext.lock().unwrap().render(self, scope);
}
}
pub fn render(&self, w: &Arc<Widget>, scope: &mut RenderScope) {
for ext in self.screen.extensions.lock().unwrap().iter() {
ext.lock().unwrap().render_widget(self, scope, w);
+12 -39
View File
@@ -32,8 +32,8 @@
use std::sync::{Arc, Mutex};
use crate::{
extensions::{Extension, Handler},
prelude::Context,
extensions::Extension,
prelude::{Context, ElementRenderer},
render_scope::RenderScope,
widget::{BoxedElement, DynWidget, Element, StaticWidget, Widget, WidgetLoad},
};
@@ -180,47 +180,19 @@ impl Screen {
/// This method is called internally by `run`.
pub fn render(self: &Arc<Self>, ctx: &Context) -> std::io::Result<()> {
let mut scope = RenderScope::new();
let mut renderer = ScreenRenderer;
let (w, h) = crossterm::terminal::size().unwrap();
scope.set_parent_size(w, h);
for ext in self.extensions.lock().unwrap().iter() {
ext.lock().unwrap().render(ctx, &mut scope);
}
ctx.render_root(&mut scope);
utils::clear()?;
for elem in self.widgets.lock().unwrap().iter() {
if elem.get::<NoRender>().is_some() || elem.get::<NoRenderRoot>().is_some() {
elem.auto_refresh();
for widget in self.widgets.lock().unwrap().iter() {
if widget.get::<NoRenderRoot>().is_some() {
widget.auto_refresh();
continue;
}
if let Some(wrapper) = elem.get::<Handler<RenderWrapperEvent>>() {
wrapper.call(elem, &RenderWrapperEvent(&mut scope));
} else {
scope.clear();
if let Some(style) = elem.get() {
scope.set_style(style);
}
if let Some(t) = elem.get() {
scope.set_transform(&t);
}
for ext in self.extensions.lock().unwrap().iter() {
ext.lock().unwrap().render_widget(ctx, &mut scope, elem);
}
elem.get_elem().render(&mut scope, ctx);
if let Some(t) = elem.get() {
scope.set_transform(&t);
}
scope.draw();
elem.get_elem().after_render(&mut scope, ctx);
}
elem.auto_refresh();
scope.render_widget(&mut renderer, ctx, widget);
}
Ok(())
}
@@ -228,13 +200,14 @@ impl Screen {
/// Closes the loop and calls `on_close` in the extensions
pub fn close(self: &Arc<Self>) {
*self.running.lock().unwrap() = false;
utils::show_cursor().unwrap();
utils::clear().unwrap();
for ext in self.extensions.lock().unwrap().iter() {
ext.lock().unwrap().on_close();
}
}
}
struct ScreenRenderer;
impl ElementRenderer for ScreenRenderer {}
+53 -1
View File
@@ -8,13 +8,22 @@
//!
//! Used internally by OSUI's layout and rendering system.
use std::fmt::Debug;
use std::{fmt::Debug, sync::Arc};
use crate::{
prelude::{Context, Handler},
style::{RawTransform, Style, Transform},
utils::{self, hex_ansi_bg},
widget::Widget,
NoRender, RenderWrapperEvent,
};
pub trait ElementRenderer {
/// Called right after the `after_render` function is called
#[allow(unused)]
fn before_draw(&mut self, scope: &mut RenderScope, widget: &Arc<Widget>) {}
}
/// Represents a single render instruction.
#[derive(Clone)]
enum RenderMethod {
@@ -291,6 +300,49 @@ impl RenderScope {
pub fn get_style(&mut self) -> &mut Style {
&mut self.style
}
pub fn render_widget(
&mut self,
renderer: &mut dyn ElementRenderer,
ctx: &Context,
widget: &std::sync::Arc<crate::widget::Widget>,
) -> bool {
if widget.get::<NoRender>().is_some() {
widget.auto_refresh();
return false;
}
if let Some(wrapper) = widget.get::<Handler<RenderWrapperEvent>>() {
wrapper.call(widget, &RenderWrapperEvent(self));
} else {
self.clear();
if let Some(style) = widget.get() {
self.set_style(style);
}
if let Some(t) = widget.get() {
self.set_transform(&t);
}
widget.get_elem().render(self, ctx);
ctx.render(widget, self);
if let Some(t) = widget.get() {
self.set_transform(&t);
}
renderer.before_draw(self, widget);
self.draw();
widget.get_elem().after_render(self, ctx);
ctx.after_render(widget, self);
}
widget.auto_refresh();
true
}
}
impl Debug for RenderScope {