add focusing to chain; nested focus works for the most part

This commit is contained in:
🪞👃🪞 2024-06-20 22:18:08 +03:00
parent 7b568c55b8
commit 5082bf9fdf
4 changed files with 98 additions and 21 deletions

View file

@ -2,16 +2,18 @@ use crate::prelude::*;
pub struct Chain { pub struct Chain {
name: String, name: String,
devices: Vec<Box<dyn Device>>, focused: bool,
focused: usize, focus: usize,
items: Vec<Box<dyn Device>>,
} }
impl Chain { impl Chain {
pub fn new (name: &str, devices: Vec<Box<dyn Device>>) -> Result<DynamicDevice<Self>, Box<dyn Error>> { pub fn new (name: &str, items: Vec<Box<dyn Device>>) -> Result<DynamicDevice<Self>, Box<dyn Error>> {
Ok(DynamicDevice::new(render, handle, process, Self { Ok(DynamicDevice::new(render, handle, process, Self {
name: name.into(), name: name.into(),
devices, focused: false,
focused: 0 focus: 0,
items,
})) }))
} }
} }
@ -30,13 +32,20 @@ pub fn render (state: &Chain, buf: &mut Buffer, area: Rect)
buf.set_string(area.x + area.width - 1, y, "", Style::default().black()); buf.set_string(area.x + area.width - 1, y, "", Style::default().black());
buf.set_string(area.x + 2, y, "Input...", Style::default().dim()); buf.set_string(area.x + 2, y, "Input...", Style::default().dim());
let mut x = 0u16; let mut x = 0u16;
for device in state.devices.iter() { for (i, device) in state.items.iter().enumerate() {
let result = device.render(buf, Rect { let result = device.render(buf, Rect {
x: area.x, x: area.x,
y, y,
width: area.width, width: area.width,
height: 21//area.height.saturating_sub(y) height: 21//area.height.saturating_sub(y)
})?; })?;
if i == state.focus {
if state.focused {
draw_box_styled(buf, result, Some(Style::default().green().not_dim()))
} else {
draw_box_styled_dotted(buf, result, Some(Style::default().green().dim()))
};
};
//let result = Rect { x: 0, y: 0, width: result.width, height: 21 }; //let result = Rect { x: 0, y: 0, width: result.width, height: 21 };
x = x.max(result.width); x = x.max(result.width);
y = y + result.height; y = y + result.height;
@ -57,6 +66,55 @@ pub fn render (state: &Chain, buf: &mut Buffer, area: Rect)
})) }))
} }
pub fn handle (_: &mut Chain, _: &AppEvent) -> Usually<bool> { impl Focus for Chain {
Ok(false) fn focused (&self) -> Option<&Box<dyn Device>> {
match self.focused {
true => self.items.get(self.focus),
false => None
}
}
fn focused_mut (&mut self) -> Option<&mut Box<dyn Device>> {
match self.focused {
true => self.items.get_mut(self.focus),
false => None
}
}
fn handle_focus (&mut self, event: &FocusEvent) -> Usually<bool> {
match event {
FocusEvent::Backward => {
if self.focus == 0 {
self.focus = self.items.len();
}
self.focus = self.focus - 1;
},
FocusEvent::Forward => {
self.focus = self.focus + 1;
if self.focus >= self.items.len() {
self.focus = 0;
}
},
FocusEvent::Inward => {
self.focused = true;
self.items[self.focus].handle(&AppEvent::Focus)?;
},
FocusEvent::Outward => {
self.focused = false;
self.items[self.focus].handle(&AppEvent::Blur)?;
},
};
Ok(true)
}
}
pub fn handle (state: &mut Chain, event: &AppEvent) -> Usually<bool> {
handle_focus(state, event, keymap!(Chain {
[Up, NONE, "focus_up", "focus row above",
|s: &mut Chain|s.handle_focus(&FocusEvent::Backward)],
[Down, NONE, "focus_down", "focus row below",
|s: &mut Chain|s.handle_focus(&FocusEvent::Forward)],
[Enter, NONE, "focus_down", "focus row below",
|s: &mut Chain|s.handle_focus(&FocusEvent::Inward)],
[Esc, NONE, "focus_down", "focus row below",
|s: &mut Chain|s.handle_focus(&FocusEvent::Outward)]
}))
} }

View file

@ -55,6 +55,22 @@ pub fn draw_box (buffer: &mut Buffer, area: Rect) -> Rect {
} }
pub fn draw_box_styled (buffer: &mut Buffer, area: Rect, style: Option<Style>) -> Rect { pub fn draw_box_styled (buffer: &mut Buffer, area: Rect, style: Option<Style>) -> Rect {
if area.width < 1 || area.height < 1 {
return area
}
let style = style.unwrap_or(Style::default());
let top = format!("{}", "".repeat((area.width - 2).into()));
let bottom = format!("{}", "".repeat((area.width - 2).into()));
buffer.set_string(area.x, area.y, top, style);
for y in (area.y + 1)..(area.y + area.height - 1) {
buffer.set_string(area.x, y, format!(""), style);
buffer.set_string(area.x + area.width - 1, y, format!(""), style);
}
buffer.set_string(area.x, area.y + area.height - 1, bottom, style);
area
}
pub fn draw_box_styled_dotted (buffer: &mut Buffer, area: Rect, style: Option<Style>) -> Rect {
if area.width < 1 || area.height < 1 { if area.width < 1 || area.height < 1 {
return area return area
} }

View file

@ -6,14 +6,14 @@ pub trait Focus {
fn handle_focus (&mut self, event: &FocusEvent) -> Usually<bool>; fn handle_focus (&mut self, event: &FocusEvent) -> Usually<bool>;
} }
enum FocusEvent { pub enum FocusEvent {
Forward, Forward,
Backward, Backward,
Inward, Inward,
Outward, Outward,
} }
fn handle_focus <T: Device + Focus> ( pub fn handle_focus <T: Focus> (
state: &mut T, state: &mut T,
event: &AppEvent, event: &AppEvent,
keymap: &[KeyBinding<T>] keymap: &[KeyBinding<T>]
@ -156,12 +156,12 @@ impl Device for Rows {
height: area.height - h height: area.height - h
})?; })?;
if i == self.focus { if i == self.focus {
draw_box_styled(buf, result, Some(if true || self.focused { if self.focused {
Style::default().green() draw_box_styled(buf, result, Some(Style::default().green().not_dim()))
} else { } else {
Style::default() draw_box_styled_dotted(buf, result, Some(Style::default().green().dim()))
})); };
} };
w = w.max(result.width); w = w.max(result.width);
h = h + result.height; h = h + result.height;
} }
@ -194,12 +194,12 @@ impl Device for Columns {
height: area.height height: area.height
})?; })?;
if i == self.focus { if i == self.focus {
draw_box_styled(buf, result, Some(if true || self.focused { if self.focused {
Style::default().green() draw_box_styled(buf, result, Some(Style::default().green().not_dim()))
} else { } else {
Style::default() draw_box_styled_dotted(buf, result, Some(Style::default().green().dim()))
})); };
} };
w = w + result.width; w = w + result.width;
h = h.max(result.height); h = h.max(result.height);
} }

View file

@ -12,7 +12,10 @@ pub use crate::time::*;
pub use crate::layout::{ pub use crate::layout::{
Rows, Rows,
Columns Columns,
Focus,
FocusEvent,
handle_focus
}; };
pub use std::error::Error; pub use std::error::Error;