mirror of
https://github.com/ClementTsang/bottom.git
synced 2025-07-27 07:34:27 +02:00
oh nyo
This commit is contained in:
parent
190615cd35
commit
c1bbe7627d
12
src/app.rs
12
src/app.rs
@ -29,7 +29,7 @@ use frozen_state::FrozenState;
|
|||||||
use crate::{
|
use crate::{
|
||||||
canvas::Painter,
|
canvas::Painter,
|
||||||
constants,
|
constants,
|
||||||
tuine::{Application, ComponentContext, Element, Flex},
|
tuine::{Application, Element, Flex, ViewContext},
|
||||||
units::data_units::DataUnit,
|
units::data_units::DataUnit,
|
||||||
Pid,
|
Pid,
|
||||||
};
|
};
|
||||||
@ -234,22 +234,22 @@ impl Application for AppState {
|
|||||||
self.terminator.load(SeqCst)
|
self.terminator.load(SeqCst)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view(&mut self) -> Element<'static, Self::Message> {
|
fn view<'b>(&mut self, ctx: &mut ViewContext<'_>) -> Element<'static, Self::Message> {
|
||||||
use crate::tuine::FlexElement;
|
use crate::tuine::FlexElement;
|
||||||
use crate::tuine::TextTable;
|
use crate::tuine::TextTable;
|
||||||
|
|
||||||
Flex::column()
|
Flex::column()
|
||||||
.with_flex_child(
|
.with_flex_child(
|
||||||
Flex::row_with_children(vec![
|
Flex::row_with_children(vec![
|
||||||
FlexElement::new(TextTable::new(vec!["A", "B", "C"])),
|
FlexElement::new(TextTable::new(ctx, vec!["A", "B", "C"])),
|
||||||
FlexElement::new(TextTable::new(vec!["D", "E", "F"])),
|
FlexElement::new(TextTable::new(ctx, vec!["D", "E", "F"])),
|
||||||
]),
|
]),
|
||||||
1,
|
1,
|
||||||
)
|
)
|
||||||
.with_flex_child(
|
.with_flex_child(
|
||||||
Flex::row_with_children(vec![
|
Flex::row_with_children(vec![
|
||||||
FlexElement::new(TextTable::new(vec!["G", "H", "I", "J"])),
|
FlexElement::new(TextTable::new(ctx, vec!["G", "H", "I", "J"])),
|
||||||
FlexElement::new(TextTable::new(vec!["K", "L", "M", "N"])),
|
FlexElement::new(TextTable::new(ctx, vec!["K", "L", "M", "N"])),
|
||||||
]),
|
]),
|
||||||
2,
|
2,
|
||||||
)
|
)
|
||||||
|
@ -4,7 +4,7 @@ use tui::Terminal;
|
|||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
runtime::{self, RuntimeEvent},
|
runtime::{self, RuntimeEvent},
|
||||||
ComponentContext, Element, Event,
|
Element, Event, ViewContext,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// An alias to the [`tui::backend::CrosstermBackend`] writing to [`std::io::Stdout`].
|
/// An alias to the [`tui::backend::CrosstermBackend`] writing to [`std::io::Stdout`].
|
||||||
@ -21,7 +21,7 @@ pub trait Application: Sized {
|
|||||||
/// always returning false.
|
/// always returning false.
|
||||||
fn is_terminated(&self) -> bool;
|
fn is_terminated(&self) -> bool;
|
||||||
|
|
||||||
fn view(&mut self) -> Element<'static, Self::Message>;
|
fn view<'b>(&mut self, ctx: &mut ViewContext<'_>) -> Element<'static, Self::Message>;
|
||||||
|
|
||||||
/// To run upon stopping the application.
|
/// To run upon stopping the application.
|
||||||
fn destroy(&mut self) {}
|
fn destroy(&mut self) {}
|
||||||
|
@ -14,7 +14,7 @@ use unicode_segmentation::UnicodeSegmentation;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
constants::TABLE_GAP_HEIGHT_LIMIT,
|
constants::TABLE_GAP_HEIGHT_LIMIT,
|
||||||
tuine::{ComponentContext, DrawContext, Event, Status, TmpComponent},
|
tuine::{DrawContext, Event, Status, TmpComponent, ViewContext},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use self::table_column::{TextColumn, TextColumnConstraint};
|
pub use self::table_column::{TextColumn, TextColumnConstraint};
|
||||||
@ -29,6 +29,7 @@ pub struct StyleSheet {
|
|||||||
|
|
||||||
/// A sortable, scrollable table for text data.
|
/// A sortable, scrollable table for text data.
|
||||||
pub struct TextTable<'a, Message> {
|
pub struct TextTable<'a, Message> {
|
||||||
|
test_state: &'a mut TextTableState,
|
||||||
state: TextTableState,
|
state: TextTableState,
|
||||||
column_widths: Vec<u16>,
|
column_widths: Vec<u16>,
|
||||||
columns: Vec<TextColumn>,
|
columns: Vec<TextColumn>,
|
||||||
@ -44,11 +45,12 @@ pub struct TextTable<'a, Message> {
|
|||||||
|
|
||||||
impl<'a, Message> TextTable<'a, Message> {
|
impl<'a, Message> TextTable<'a, Message> {
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn new<S: Into<Cow<'static, str>>>(columns: Vec<S>) -> Self {
|
pub fn new<S: Into<Cow<'static, str>>>(ctx: &mut ViewContext<'_>, columns: Vec<S>) -> Self {
|
||||||
let state = TextTableState::default();
|
let test_state = ctx.state::<TextTableState>(Location::caller());
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
state,
|
test_state,
|
||||||
|
state: TextTableState::default(),
|
||||||
column_widths: vec![0; columns.len()],
|
column_widths: vec![0; columns.len()],
|
||||||
columns: columns
|
columns: columns
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use std::panic::Location;
|
use std::{panic::Location, rc::Rc};
|
||||||
|
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
use tui::layout::Rect;
|
use tui::layout::Rect;
|
||||||
@ -6,26 +6,41 @@ use tui::layout::Rect;
|
|||||||
use super::{Key, LayoutNode, State};
|
use super::{Key, LayoutNode, State};
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct ComponentContext {
|
pub struct StateMap(FxHashMap<Key, (Rc<Box<dyn State>>, bool)>);
|
||||||
key_counter: usize,
|
|
||||||
state_map: FxHashMap<Key, Box<dyn State>>,
|
impl StateMap {
|
||||||
stale_map: FxHashMap<Key, bool>,
|
pub fn state<S: State + Default + 'static>(&mut self, key: Key) -> Rc<Box<dyn State>> {
|
||||||
|
let state = self
|
||||||
|
.0
|
||||||
|
.entry(key)
|
||||||
|
.or_insert_with(|| (Rc::new(Box::new(S::default())), true));
|
||||||
|
|
||||||
|
state.1 = true;
|
||||||
|
|
||||||
|
state.0.clone()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ComponentContext {
|
pub struct ViewContext<'a> {
|
||||||
pub fn access_or_new<S: State + Default + 'static>(
|
key_counter: usize,
|
||||||
|
state_map: &'a mut StateMap,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ViewContext<'a> {
|
||||||
|
pub fn new(state_map: &'a mut StateMap) -> Self {
|
||||||
|
Self {
|
||||||
|
key_counter: 0,
|
||||||
|
state_map,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn state<S: State + Default + 'static>(
|
||||||
&mut self, location: &'static Location<'static>,
|
&mut self, location: &'static Location<'static>,
|
||||||
) -> &mut Box<dyn State> {
|
) -> Rc<Box<dyn State>> {
|
||||||
let key = Key::new(location, self.key_counter);
|
let key = Key::new(location, self.key_counter);
|
||||||
self.key_counter += 1;
|
self.key_counter += 1;
|
||||||
|
self.state_map.state::<S>(key)
|
||||||
*(self.stale_map.entry(key).or_insert(true)) = true;
|
|
||||||
self.state_map
|
|
||||||
.entry(key)
|
|
||||||
.or_insert_with(|| Box::new(S::default()))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cycle(&mut self) {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DrawContext<'a> {
|
pub struct DrawContext<'a> {
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
use std::sync::mpsc::Receiver;
|
use std::sync::mpsc::Receiver;
|
||||||
|
|
||||||
|
use rustc_hash::FxHashMap;
|
||||||
use tui::{backend::Backend, layout::Rect, Terminal};
|
use tui::{backend::Backend, layout::Rect, Terminal};
|
||||||
|
|
||||||
use crate::tuine::Status;
|
use crate::tuine::Status;
|
||||||
|
|
||||||
use super::{build_layout_tree, Application, ComponentContext, Element, Event, TmpComponent};
|
use super::{
|
||||||
|
build_layout_tree, Application, Element, Event, Key, State, StateMap, TmpComponent, ViewContext,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub enum RuntimeEvent<Message> {
|
pub enum RuntimeEvent<Message> {
|
||||||
@ -13,6 +16,11 @@ pub enum RuntimeEvent<Message> {
|
|||||||
Custom(Message),
|
Custom(Message),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct AppData {
|
||||||
|
state_map: StateMap,
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn launch<A, B>(
|
pub(crate) fn launch<A, B>(
|
||||||
mut application: A, receiver: Receiver<RuntimeEvent<A::Message>>, terminal: &mut Terminal<B>,
|
mut application: A, receiver: Receiver<RuntimeEvent<A::Message>>, terminal: &mut Terminal<B>,
|
||||||
) -> anyhow::Result<()>
|
) -> anyhow::Result<()>
|
||||||
@ -20,8 +28,13 @@ where
|
|||||||
A: Application + 'static,
|
A: Application + 'static,
|
||||||
B: Backend,
|
B: Backend,
|
||||||
{
|
{
|
||||||
let mut user_interface = application.view();
|
let mut app_data = AppData::default();
|
||||||
draw(&mut user_interface, terminal)?;
|
let mut user_interface = {
|
||||||
|
let mut ctx = ViewContext::new(&mut app_data.state_map);
|
||||||
|
let mut ui = application.view(&mut ctx);
|
||||||
|
draw(&mut ui, terminal)?;
|
||||||
|
ui
|
||||||
|
};
|
||||||
|
|
||||||
while !application.is_terminated() {
|
while !application.is_terminated() {
|
||||||
if let Ok(event) = receiver.recv() {
|
if let Ok(event) = receiver.recv() {
|
||||||
@ -42,7 +55,8 @@ where
|
|||||||
application.update(msg);
|
application.update(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
user_interface = application.view();
|
let mut ctx = ViewContext::new(&mut app_data.state_map);
|
||||||
|
user_interface = application.view(&mut ctx);
|
||||||
draw(&mut user_interface, terminal)?;
|
draw(&mut user_interface, terminal)?;
|
||||||
}
|
}
|
||||||
RuntimeEvent::Custom(message) => {
|
RuntimeEvent::Custom(message) => {
|
||||||
@ -52,7 +66,8 @@ where
|
|||||||
width: _,
|
width: _,
|
||||||
height: _,
|
height: _,
|
||||||
} => {
|
} => {
|
||||||
user_interface = application.view();
|
let mut ctx = ViewContext::new(&mut app_data.state_map);
|
||||||
|
user_interface = application.view(&mut ctx);
|
||||||
// FIXME: Also nuke any cache and the like...
|
// FIXME: Also nuke any cache and the like...
|
||||||
draw(&mut user_interface, terminal)?;
|
draw(&mut user_interface, terminal)?;
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,8 @@ use std::any::Any;
|
|||||||
pub trait State {
|
pub trait State {
|
||||||
fn as_any(&self) -> &dyn Any;
|
fn as_any(&self) -> &dyn Any;
|
||||||
|
|
||||||
|
fn as_mut_any(&mut self) -> &mut dyn Any;
|
||||||
|
|
||||||
fn are_equal(&self, other: &dyn State) -> bool;
|
fn are_equal(&self, other: &dyn State) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -15,6 +17,10 @@ impl<S: PartialEq + 'static> State for S {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn as_mut_any(&mut self) -> &mut dyn Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
fn are_equal(&self, other: &dyn State) -> bool {
|
fn are_equal(&self, other: &dyn State) -> bool {
|
||||||
other
|
other
|
||||||
.as_any()
|
.as_any()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user