+11
-1
@@ -18,7 +18,7 @@ pub fn app(screen: Arc<Screen>) -> Rsx {
|
|||||||
let screen = screen.clone();
|
let screen = screen.clone();
|
||||||
move |_, e: &crossterm::event::Event| {
|
move |_, e: &crossterm::event::Event| {
|
||||||
if let crossterm::event::Event::Key(crossterm::event::KeyEvent { code, .. }) = e {
|
if let crossterm::event::Event::Key(crossterm::event::KeyEvent { code, .. }) = e {
|
||||||
if *code == crossterm::event::KeyCode::Char('q') {
|
if *code == crossterm::event::KeyCode::Esc {
|
||||||
screen.close();
|
screen.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -51,10 +51,19 @@ pub fn app(screen: Arc<Screen>) -> Rsx {
|
|||||||
%count
|
%count
|
||||||
"This will increment every second: {count}"
|
"This will increment every second: {count}"
|
||||||
|
|
||||||
|
FlexRow
|
||||||
|
{
|
||||||
|
"Username"
|
||||||
@Transform::new().padding(1, 1).dimensions(40, 1);
|
@Transform::new().padding(1, 1).dimensions(40, 1);
|
||||||
@Style { foreground: Some(0xffffff), background: Background::RoundedOutline(0xff0000) };
|
@Style { foreground: Some(0xffffff), background: Background::RoundedOutline(0xff0000) };
|
||||||
|
@Focused;
|
||||||
Input { }
|
Input { }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transform::new().margin(0, 1);
|
||||||
|
FlexRow
|
||||||
|
{
|
||||||
|
"Password"
|
||||||
@Transform::new().padding(1, 1).dimensions(40, 1);
|
@Transform::new().padding(1, 1).dimensions(40, 1);
|
||||||
@Style { foreground: Some(0xffffff), background: Background::RoundedOutline(0xffff00) };
|
@Style { foreground: Some(0xffffff), background: Background::RoundedOutline(0xffff00) };
|
||||||
Input { }
|
Input { }
|
||||||
@@ -62,3 +71,4 @@ pub fn app(screen: Arc<Screen>) -> Rsx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|||||||
+28
-32
@@ -1,10 +1,14 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
prelude::ElementRenderer,
|
||||||
|
style::RawTransform,
|
||||||
widget::{Element, Widget},
|
widget::{Element, Widget},
|
||||||
NoRender, NoRenderRoot,
|
NoRenderRoot,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub struct DivRenderer<'a>(pub &'a mut RawTransform);
|
||||||
|
|
||||||
pub struct Div {
|
pub struct Div {
|
||||||
children: Vec<Arc<Widget>>,
|
children: Vec<Arc<Widget>>,
|
||||||
size: (u16, u16),
|
size: (u16, u16),
|
||||||
@@ -23,7 +27,7 @@ impl Element for Div {
|
|||||||
fn render(
|
fn render(
|
||||||
&mut self,
|
&mut self,
|
||||||
scope: &mut crate::render_scope::RenderScope,
|
scope: &mut crate::render_scope::RenderScope,
|
||||||
_: &crate::extensions::Context,
|
_: &crate::render_scope::RenderContext,
|
||||||
) {
|
) {
|
||||||
let (width, height) = scope.get_size_or(self.size.0, self.size.1);
|
let (width, height) = scope.get_size_or(self.size.0, self.size.1);
|
||||||
scope.use_area(width, height);
|
scope.use_area(width, height);
|
||||||
@@ -32,42 +36,20 @@ impl Element for Div {
|
|||||||
fn after_render(
|
fn after_render(
|
||||||
&mut self,
|
&mut self,
|
||||||
scope: &mut crate::render_scope::RenderScope,
|
scope: &mut crate::render_scope::RenderScope,
|
||||||
ctx: &crate::extensions::Context,
|
render_context: &crate::render_scope::RenderContext,
|
||||||
) {
|
) {
|
||||||
let mut transform = scope.get_transform().clone();
|
let mut transform = scope.get_transform().clone();
|
||||||
|
let mut renderer = DivRenderer(&mut transform);
|
||||||
|
|
||||||
let (w, h) = scope.get_parent_size();
|
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 {
|
for widget in &self.children {
|
||||||
if elem.get::<NoRender>().is_some() {
|
scope.render_widget(&mut renderer, render_context.get_context(), widget);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
scope.set_parent_size(w, h);
|
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>) {
|
fn draw_child(&mut self, element: &Arc<Widget>) {
|
||||||
@@ -75,6 +57,10 @@ impl Element for Div {
|
|||||||
element.inject(|w| w.component(NoRenderRoot));
|
element.inject(|w| w.component(NoRenderRoot));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_ghost(&mut self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
fn as_any(&self) -> &dyn std::any::Any {
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@@ -83,3 +69,13 @@ impl Element for Div {
|
|||||||
self
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+55
-66
@@ -1,10 +1,15 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
prelude::ElementRenderer,
|
||||||
|
style::RawTransform,
|
||||||
widget::{Element, Widget},
|
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 struct FlexRow {
|
||||||
pub gap: u16,
|
pub gap: u16,
|
||||||
children: Vec<Arc<Widget>>,
|
children: Vec<Arc<Widget>>,
|
||||||
@@ -41,7 +46,7 @@ impl Element for FlexRow {
|
|||||||
fn render(
|
fn render(
|
||||||
&mut self,
|
&mut self,
|
||||||
scope: &mut crate::render_scope::RenderScope,
|
scope: &mut crate::render_scope::RenderScope,
|
||||||
_: &crate::extensions::Context,
|
_: &crate::render_scope::RenderContext,
|
||||||
) {
|
) {
|
||||||
let (width, height) = scope.get_size_or(self.size.0, self.size.1);
|
let (width, height) = scope.get_size_or(self.size.0, self.size.1);
|
||||||
scope.use_area(width, height);
|
scope.use_area(width, height);
|
||||||
@@ -50,49 +55,22 @@ impl Element for FlexRow {
|
|||||||
fn after_render(
|
fn after_render(
|
||||||
&mut self,
|
&mut self,
|
||||||
scope: &mut crate::render_scope::RenderScope,
|
scope: &mut crate::render_scope::RenderScope,
|
||||||
ctx: &crate::extensions::Context,
|
render_context: &crate::render_scope::RenderContext,
|
||||||
) {
|
) {
|
||||||
let mut transform = scope.get_transform().clone();
|
let mut transform = scope.get_transform().clone();
|
||||||
let transform_before = transform.clone();
|
let transform_before = transform.clone();
|
||||||
let (w, h) = scope.get_parent_size();
|
let (w, h) = scope.get_parent_size();
|
||||||
scope.set_parent_size(transform.width, transform.height);
|
scope.set_parent_size(transform.width, transform.height);
|
||||||
|
|
||||||
let mut v = 0;
|
let mut v = 0;
|
||||||
|
|
||||||
for elem in &self.children {
|
let mut renderer = RowRenderer(&mut transform, self.gap, &mut v);
|
||||||
if elem.get::<NoRender>().is_some() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
scope.clear();
|
for widget in &self.children {
|
||||||
if let Some(style) = elem.get() {
|
scope.render_widget(&mut renderer, render_context.get_context(), widget);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
scope.set_parent_size(w, h);
|
scope.set_parent_size(w, h);
|
||||||
self.size = (transform.width, transform.height);
|
|
||||||
scope.set_transform_raw(transform_before);
|
scope.set_transform_raw(transform_before);
|
||||||
|
self.size = (transform.width, transform.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_child(&mut self, element: &Arc<Widget>) {
|
fn draw_child(&mut self, element: &Arc<Widget>) {
|
||||||
@@ -100,6 +78,10 @@ impl Element for FlexRow {
|
|||||||
element.inject(|w| w.component(NoRenderRoot));
|
element.inject(|w| w.component(NoRenderRoot));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_ghost(&mut self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
fn as_any(&self) -> &dyn std::any::Any {
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@@ -113,7 +95,7 @@ impl Element for FlexCol {
|
|||||||
fn render(
|
fn render(
|
||||||
&mut self,
|
&mut self,
|
||||||
scope: &mut crate::render_scope::RenderScope,
|
scope: &mut crate::render_scope::RenderScope,
|
||||||
_: &crate::extensions::Context,
|
_: &crate::render_scope::RenderContext,
|
||||||
) {
|
) {
|
||||||
let (width, height) = scope.get_size_or(self.size.0, self.size.1);
|
let (width, height) = scope.get_size_or(self.size.0, self.size.1);
|
||||||
scope.use_area(width, height);
|
scope.use_area(width, height);
|
||||||
@@ -122,45 +104,18 @@ impl Element for FlexCol {
|
|||||||
fn after_render(
|
fn after_render(
|
||||||
&mut self,
|
&mut self,
|
||||||
scope: &mut crate::render_scope::RenderScope,
|
scope: &mut crate::render_scope::RenderScope,
|
||||||
ctx: &crate::extensions::Context,
|
render_context: &crate::render_scope::RenderContext,
|
||||||
) {
|
) {
|
||||||
let mut transform = scope.get_transform().clone();
|
let mut transform = scope.get_transform().clone();
|
||||||
let transform_before = transform.clone();
|
let transform_before = transform.clone();
|
||||||
let (w, h) = scope.get_parent_size();
|
let (w, h) = scope.get_parent_size();
|
||||||
scope.set_parent_size(transform.width, transform.height);
|
scope.set_parent_size(transform.width, transform.height);
|
||||||
|
|
||||||
let mut v = 0;
|
let mut v = 0;
|
||||||
|
|
||||||
for elem in &self.children {
|
let mut renderer = ColumnRenderer(&mut transform, self.gap, &mut v);
|
||||||
if elem.get::<NoRender>().is_some() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
scope.clear();
|
for widget in &self.children {
|
||||||
if let Some(style) = elem.get() {
|
scope.render_widget(&mut renderer, render_context.get_context(), widget);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
scope.set_parent_size(w, h);
|
scope.set_parent_size(w, h);
|
||||||
scope.set_transform_raw(transform_before);
|
scope.set_transform_raw(transform_before);
|
||||||
@@ -172,6 +127,10 @@ impl Element for FlexCol {
|
|||||||
element.inject(|w| w.component(NoRenderRoot));
|
element.inject(|w| w.component(NoRenderRoot));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_ghost(&mut self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
fn as_any(&self) -> &dyn std::any::Any {
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@@ -180,3 +139,33 @@ impl Element for FlexCol {
|
|||||||
self
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ impl Element for Heading {
|
|||||||
fn render(
|
fn render(
|
||||||
&mut self,
|
&mut self,
|
||||||
scope: &mut crate::prelude::RenderScope,
|
scope: &mut crate::prelude::RenderScope,
|
||||||
_: &crate::extensions::Context,
|
_: &crate::render_scope::RenderContext,
|
||||||
) {
|
) {
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
for element in &self.children {
|
for element in &self.children {
|
||||||
@@ -57,6 +57,10 @@ impl Element for Heading {
|
|||||||
self.children.push(element.clone());
|
self.children.push(element.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_ghost(&mut self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
fn as_any(&self) -> &dyn std::any::Any {
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,16 +14,18 @@ impl Element for Input {
|
|||||||
fn render(
|
fn render(
|
||||||
&mut self,
|
&mut self,
|
||||||
scope: &mut crate::prelude::RenderScope,
|
scope: &mut crate::prelude::RenderScope,
|
||||||
_: &crate::extensions::Context,
|
render_context: &crate::render_scope::RenderContext,
|
||||||
) {
|
) {
|
||||||
let s = self.state.get();
|
let s = self.state.get();
|
||||||
scope.draw_text(0, 0, &s);
|
scope.draw_text(0, 0, &s);
|
||||||
|
if render_context.is_focused() {
|
||||||
if let Some(c) = s.chars().nth(self.cursor) {
|
if let Some(c) = s.chars().nth(self.cursor) {
|
||||||
scope.draw_text_inverted(self.cursor as u16, 0, &c.to_string());
|
scope.draw_text_inverted(self.cursor as u16, 0, &c.to_string());
|
||||||
} else {
|
} else {
|
||||||
scope.draw_text_inverted(s.len() as u16, 0, " ");
|
scope.draw_text_inverted(s.len() as u16, 0, " ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn event(&mut self, event: &dyn crate::prelude::Event) {
|
fn event(&mut self, event: &dyn crate::prelude::Event) {
|
||||||
if let Some(crossterm::event::Event::Key(KeyEvent {
|
if let Some(crossterm::event::Event::Key(KeyEvent {
|
||||||
|
|||||||
+5
-1
@@ -16,11 +16,15 @@ impl Element for String {
|
|||||||
fn render(
|
fn render(
|
||||||
&mut self,
|
&mut self,
|
||||||
scope: &mut crate::render_scope::RenderScope,
|
scope: &mut crate::render_scope::RenderScope,
|
||||||
_: &crate::extensions::Context,
|
_: &crate::render_scope::RenderContext,
|
||||||
) {
|
) {
|
||||||
scope.draw_text(0, 0, self);
|
scope.draw_text(0, 0, self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_ghost(&mut self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
fn as_any(&self) -> &dyn std::any::Any {
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-30
@@ -3,8 +3,9 @@ use std::sync::Arc;
|
|||||||
use crossterm::event::{KeyCode, KeyEvent};
|
use crossterm::event::{KeyCode, KeyEvent};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
prelude::DivRenderer,
|
||||||
widget::{Element, Widget},
|
widget::{Element, Widget},
|
||||||
NoRender, NoRenderRoot,
|
NoRenderRoot,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct Paginator {
|
pub struct Paginator {
|
||||||
@@ -27,7 +28,7 @@ impl Element for Paginator {
|
|||||||
fn render(
|
fn render(
|
||||||
&mut self,
|
&mut self,
|
||||||
scope: &mut crate::render_scope::RenderScope,
|
scope: &mut crate::render_scope::RenderScope,
|
||||||
_: &crate::extensions::Context,
|
_: &crate::render_scope::RenderContext,
|
||||||
) {
|
) {
|
||||||
let (width, height) = scope.get_size_or(self.size.0, self.size.1);
|
let (width, height) = scope.get_size_or(self.size.0, self.size.1);
|
||||||
scope.use_area(width, height);
|
scope.use_area(width, height);
|
||||||
@@ -36,40 +37,18 @@ impl Element for Paginator {
|
|||||||
fn after_render(
|
fn after_render(
|
||||||
&mut self,
|
&mut self,
|
||||||
scope: &mut crate::render_scope::RenderScope,
|
scope: &mut crate::render_scope::RenderScope,
|
||||||
ctx: &crate::extensions::Context,
|
render_context: &crate::render_scope::RenderContext,
|
||||||
) {
|
) {
|
||||||
if let Some(elem) = self.children.get(self.index) {
|
if let Some(widget) = self.children.get(self.index) {
|
||||||
if elem.get::<NoRender>().is_some() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut transform = scope.get_transform().clone();
|
let mut transform = scope.get_transform().clone();
|
||||||
|
let mut renderer = DivRenderer(&mut transform);
|
||||||
let (w, h) = scope.get_parent_size();
|
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);
|
||||||
scope.clear();
|
|
||||||
|
|
||||||
if let Some(style) = elem.get() {
|
scope.render_widget(&mut renderer, render_context.get_context(), widget);
|
||||||
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.set_parent_size(w, h);
|
scope.set_parent_size(w, h);
|
||||||
self.size = (transform.width, transform.height);
|
self.size = (renderer.0.width, renderer.0.height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,6 +75,10 @@ impl Element for Paginator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_ghost(&mut self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
fn draw_child(&mut self, element: &Arc<Widget>) {
|
fn draw_child(&mut self, element: &Arc<Widget>) {
|
||||||
self.children.push(element.clone());
|
self.children.push(element.clone());
|
||||||
element.inject(|w| w.component(NoRenderRoot));
|
element.inject(|w| w.component(NoRenderRoot));
|
||||||
|
|||||||
+11
-2
@@ -7,6 +7,7 @@ use super::Extension;
|
|||||||
use crossterm::event::{Event as CrosstermEvent, KeyCode, KeyModifiers};
|
use crossterm::event::{Event as CrosstermEvent, KeyCode, KeyModifiers};
|
||||||
|
|
||||||
component!(AlwaysFocused);
|
component!(AlwaysFocused);
|
||||||
|
component!(Focused);
|
||||||
|
|
||||||
enum Direction {
|
enum Direction {
|
||||||
Left,
|
Left,
|
||||||
@@ -21,6 +22,14 @@ pub struct RelativeFocusExtension {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Extension for RelativeFocusExtension {
|
impl Extension for RelativeFocusExtension {
|
||||||
|
fn init(&mut self, _ctx: &super::Context) {
|
||||||
|
for widget in _ctx.get_widgets().iter() {
|
||||||
|
if let Some(Focused) = widget.get() {
|
||||||
|
widget.set_focused(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn event(&mut self, ctx: &super::Context, event: &dyn super::Event) {
|
fn event(&mut self, ctx: &super::Context, event: &dyn super::Event) {
|
||||||
if let Some(e) = event.get::<CrosstermEvent>() {
|
if let Some(e) = event.get::<CrosstermEvent>() {
|
||||||
match e {
|
match e {
|
||||||
@@ -109,7 +118,7 @@ impl Extension for RelativeFocusExtension {
|
|||||||
for (i, w) in ctx.get_widgets().iter().enumerate() {
|
for (i, w) in ctx.get_widgets().iter().enumerate() {
|
||||||
if let Some(AlwaysFocused) = w.get() {
|
if let Some(AlwaysFocused) = w.get() {
|
||||||
w.set_focused(true);
|
w.set_focused(true);
|
||||||
} else {
|
} else if !w.is_ghost() {
|
||||||
w.set_focused(i == self.cursor);
|
w.set_focused(i == self.cursor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -145,7 +154,7 @@ impl Extension for RelativeFocusExtension {
|
|||||||
if let Some(p) = ctx
|
if let Some(p) = ctx
|
||||||
.get_widgets()
|
.get_widgets()
|
||||||
.iter()
|
.iter()
|
||||||
.position(|w| Arc::ptr_eq(w, &widget))
|
.position(|w| Arc::ptr_eq(w, &widget) && !w.is_ghost())
|
||||||
{
|
{
|
||||||
rendered.lock().unwrap().push((p, t.x, t.y));
|
rendered.lock().unwrap().push((p, t.x, t.y));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -119,6 +119,12 @@ impl Context {
|
|||||||
components
|
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) {
|
pub fn render(&self, w: &Arc<Widget>, scope: &mut RenderScope) {
|
||||||
for ext in self.screen.extensions.lock().unwrap().iter() {
|
for ext in self.screen.extensions.lock().unwrap().iter() {
|
||||||
ext.lock().unwrap().render_widget(self, scope, w);
|
ext.lock().unwrap().render_widget(self, scope, w);
|
||||||
|
|||||||
+12
-39
@@ -32,8 +32,8 @@
|
|||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
extensions::{Extension, Handler},
|
extensions::Extension,
|
||||||
prelude::Context,
|
prelude::{Context, ElementRenderer},
|
||||||
render_scope::RenderScope,
|
render_scope::RenderScope,
|
||||||
widget::{BoxedElement, DynWidget, Element, StaticWidget, Widget, WidgetLoad},
|
widget::{BoxedElement, DynWidget, Element, StaticWidget, Widget, WidgetLoad},
|
||||||
};
|
};
|
||||||
@@ -180,47 +180,19 @@ impl Screen {
|
|||||||
/// This method is called internally by `run`.
|
/// This method is called internally by `run`.
|
||||||
pub fn render(self: &Arc<Self>, ctx: &Context) -> std::io::Result<()> {
|
pub fn render(self: &Arc<Self>, ctx: &Context) -> std::io::Result<()> {
|
||||||
let mut scope = RenderScope::new();
|
let mut scope = RenderScope::new();
|
||||||
|
let mut renderer = ScreenRenderer;
|
||||||
let (w, h) = crossterm::terminal::size().unwrap();
|
let (w, h) = crossterm::terminal::size().unwrap();
|
||||||
scope.set_parent_size(w, h);
|
scope.set_parent_size(w, h);
|
||||||
|
ctx.render_root(&mut scope);
|
||||||
for ext in self.extensions.lock().unwrap().iter() {
|
|
||||||
ext.lock().unwrap().render(ctx, &mut scope);
|
|
||||||
}
|
|
||||||
|
|
||||||
utils::clear()?;
|
utils::clear()?;
|
||||||
for elem in self.widgets.lock().unwrap().iter() {
|
for widget in self.widgets.lock().unwrap().iter() {
|
||||||
if elem.get::<NoRender>().is_some() || elem.get::<NoRenderRoot>().is_some() {
|
if widget.get::<NoRenderRoot>().is_some() {
|
||||||
elem.auto_refresh();
|
widget.auto_refresh();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(wrapper) = elem.get::<Handler<RenderWrapperEvent>>() {
|
scope.render_widget(&mut renderer, ctx, widget);
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -228,13 +200,14 @@ impl Screen {
|
|||||||
/// Closes the loop and calls `on_close` in the extensions
|
/// Closes the loop and calls `on_close` in the extensions
|
||||||
pub fn close(self: &Arc<Self>) {
|
pub fn close(self: &Arc<Self>) {
|
||||||
*self.running.lock().unwrap() = false;
|
*self.running.lock().unwrap() = false;
|
||||||
|
|
||||||
utils::show_cursor().unwrap();
|
utils::show_cursor().unwrap();
|
||||||
|
|
||||||
utils::clear().unwrap();
|
utils::clear().unwrap();
|
||||||
|
|
||||||
for ext in self.extensions.lock().unwrap().iter() {
|
for ext in self.extensions.lock().unwrap().iter() {
|
||||||
ext.lock().unwrap().on_close();
|
ext.lock().unwrap().on_close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ScreenRenderer;
|
||||||
|
|
||||||
|
impl ElementRenderer for ScreenRenderer {}
|
||||||
|
|||||||
+79
-1
@@ -8,13 +8,22 @@
|
|||||||
//!
|
//!
|
||||||
//! Used internally by OSUI's layout and rendering system.
|
//! Used internally by OSUI's layout and rendering system.
|
||||||
|
|
||||||
use std::fmt::Debug;
|
use std::{fmt::Debug, sync::Arc};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
prelude::{Context, Handler},
|
||||||
style::{RawTransform, Style, Transform},
|
style::{RawTransform, Style, Transform},
|
||||||
utils::{self, hex_ansi_bg},
|
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.
|
/// Represents a single render instruction.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
enum RenderMethod {
|
enum RenderMethod {
|
||||||
@@ -41,6 +50,30 @@ pub struct RenderScope {
|
|||||||
style: Style,
|
style: Style,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct RenderContext(Context, bool);
|
||||||
|
|
||||||
|
impl RenderContext {
|
||||||
|
pub fn new(c: &Context, focused: bool) -> Self {
|
||||||
|
Self(c.clone(), focused)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_focused(&self) -> bool {
|
||||||
|
self.1
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render(&self, w: &Arc<Widget>, scope: &mut RenderScope) {
|
||||||
|
self.0.render(w, scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn after_render(&self, w: &Arc<Widget>, scope: &mut RenderScope) {
|
||||||
|
self.0.after_render(w, scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_context(&self) -> &Context {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl RenderScope {
|
impl RenderScope {
|
||||||
/// Creates a new, empty `RenderScope`.
|
/// Creates a new, empty `RenderScope`.
|
||||||
pub fn new() -> RenderScope {
|
pub fn new() -> RenderScope {
|
||||||
@@ -291,6 +324,51 @@ impl RenderScope {
|
|||||||
pub fn get_style(&mut self) -> &mut Style {
|
pub fn get_style(&mut self) -> &mut Style {
|
||||||
&mut self.style
|
&mut self.style
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn render_widget(
|
||||||
|
&mut self,
|
||||||
|
renderer: &mut dyn ElementRenderer,
|
||||||
|
ctx: &crate::extensions::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();
|
||||||
|
|
||||||
|
let render_context = RenderContext::new(ctx, widget.is_focused());
|
||||||
|
|
||||||
|
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, &render_context);
|
||||||
|
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, &render_context);
|
||||||
|
ctx.after_render(widget, self);
|
||||||
|
}
|
||||||
|
|
||||||
|
widget.auto_refresh();
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for RenderScope {
|
impl Debug for RenderScope {
|
||||||
|
|||||||
+23
-2
@@ -31,11 +31,21 @@ pub type BoxedComponent = Box<dyn Component + Send + Sync>;
|
|||||||
pub trait Element: Send + Sync {
|
pub trait Element: Send + Sync {
|
||||||
/// Called to perform rendering for the element.
|
/// Called to perform rendering for the element.
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
fn render(&mut self, scope: &mut RenderScope, ctx: &crate::extensions::Context) {}
|
fn render(
|
||||||
|
&mut self,
|
||||||
|
scope: &mut RenderScope,
|
||||||
|
render_context: &crate::render_scope::RenderContext,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
/// Called after rendering, for follow-up logic or cleanup.
|
/// Called after rendering, for follow-up logic or cleanup.
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
fn after_render(&mut self, scope: &mut RenderScope, ctx: &crate::extensions::Context) {}
|
fn after_render(
|
||||||
|
&mut self,
|
||||||
|
scope: &mut RenderScope,
|
||||||
|
render_context: &crate::render_scope::RenderContext,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
/// Called to draw child widgets, if any.
|
/// Called to draw child widgets, if any.
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
@@ -44,6 +54,10 @@ pub trait Element: Send + Sync {
|
|||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
fn event(&mut self, event: &dyn Event) {}
|
fn event(&mut self, event: &dyn Event) {}
|
||||||
|
|
||||||
|
fn is_ghost(&mut self) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a type-erased reference to this object.
|
/// Returns a type-erased reference to this object.
|
||||||
fn as_any(&self) -> &dyn Any;
|
fn as_any(&self) -> &dyn Any;
|
||||||
|
|
||||||
@@ -138,6 +152,13 @@ impl Widget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_ghost(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Self::Dynamic(w) => w.element.lock().unwrap().is_ghost(),
|
||||||
|
Self::Static(w) => w.element.lock().unwrap().is_ghost(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_focused(&self, f: bool) {
|
pub fn set_focused(&self, f: bool) {
|
||||||
match self {
|
match self {
|
||||||
Self::Dynamic(w) => *w.focused.lock().unwrap() = f,
|
Self::Dynamic(w) => *w.focused.lock().unwrap() = f,
|
||||||
|
|||||||
Reference in New Issue
Block a user