Added ghost elements to avoid focusing on them

This commit is contained in:
2025-08-09 02:27:16 +02:00
parent c8ebe36d78
commit 3520369e35
7 changed files with 75 additions and 11 deletions
+10
View File
@@ -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 {
} }
} }
} }
}
+4
View File
@@ -57,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
} }
+8
View File
@@ -78,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
} }
@@ -123,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
} }
+4
View File
@@ -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
} }
+4
View File
@@ -21,6 +21,10 @@ impl Element for String {
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
} }
+10 -1
View File
@@ -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 {
@@ -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));
} }
+29 -4
View File
@@ -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, render_context: &crate::render_scope::RenderContext) {} 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, render_context: &crate::render_scope::RenderContext) {} 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,10 +152,21 @@ 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) => {
Self::Static(w) => *w.focused.lock().unwrap() = f, *w.focused.lock().unwrap() = f && !w.element.lock().unwrap().is_ghost()
}
Self::Static(w) => {
*w.focused.lock().unwrap() = f && !w.element.lock().unwrap().is_ghost()
}
} }
} }