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
+16 -6
View File
@@ -51,13 +51,23 @@ pub fn app(screen: Arc<Screen>) -> Rsx {
%count
"This will increment every second: {count}"
@Transform::new().padding(1, 1).dimensions(40, 1);
@Style { foreground: Some(0xffffff), background: Background::RoundedOutline(0xff0000) };
Input { }
FlexRow
{
"Username"
@Transform::new().padding(1, 1).dimensions(40, 1);
@Style { foreground: Some(0xffffff), background: Background::RoundedOutline(0xff0000) };
@Focused;
Input { }
}
@Transform::new().padding(1, 1).dimensions(40, 1);
@Style { foreground: Some(0xffffff), background: Background::RoundedOutline(0xffff00) };
Input { }
@Transform::new().margin(0, 1);
FlexRow
{
"Password"
@Transform::new().padding(1, 1).dimensions(40, 1);
@Style { foreground: Some(0xffffff), background: Background::RoundedOutline(0xffff00) };
Input { }
}
}
}
}
+4
View File
@@ -57,6 +57,10 @@ impl Element for Div {
element.inject(|w| w.component(NoRenderRoot));
}
fn is_ghost(&mut self) -> bool {
true
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
+8
View File
@@ -78,6 +78,10 @@ impl Element for FlexRow {
element.inject(|w| w.component(NoRenderRoot));
}
fn is_ghost(&mut self) -> bool {
true
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
@@ -123,6 +127,10 @@ impl Element for FlexCol {
element.inject(|w| w.component(NoRenderRoot));
}
fn is_ghost(&mut self) -> bool {
true
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
+4
View File
@@ -57,6 +57,10 @@ impl Element for Heading {
self.children.push(element.clone());
}
fn is_ghost(&mut self) -> bool {
true
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
+4
View File
@@ -21,6 +21,10 @@ impl Element for String {
scope.draw_text(0, 0, self);
}
fn is_ghost(&mut self) -> bool {
true
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
+10 -1
View File
@@ -7,6 +7,7 @@ use super::Extension;
use crossterm::event::{Event as CrosstermEvent, KeyCode, KeyModifiers};
component!(AlwaysFocused);
component!(Focused);
enum Direction {
Left,
@@ -21,6 +22,14 @@ pub struct 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) {
if let Some(e) = event.get::<CrosstermEvent>() {
match e {
@@ -145,7 +154,7 @@ impl Extension for RelativeFocusExtension {
if let Some(p) = ctx
.get_widgets()
.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));
}
+29 -4
View File
@@ -31,11 +31,21 @@ pub type BoxedComponent = Box<dyn Component + Send + Sync>;
pub trait Element: Send + Sync {
/// Called to perform rendering for the element.
#[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.
#[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.
#[allow(unused)]
@@ -44,6 +54,10 @@ pub trait Element: Send + Sync {
#[allow(unused)]
fn event(&mut self, event: &dyn Event) {}
fn is_ghost(&mut self) -> bool {
false
}
/// Returns a type-erased reference to this object.
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) {
match self {
Self::Dynamic(w) => *w.focused.lock().unwrap() = f,
Self::Static(w) => *w.focused.lock().unwrap() = f,
Self::Dynamic(w) => {
*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()
}
}
}