ui: organize functions into structs

for now we have the following hierarchy:

    ListObject
    NetFrame
    NetWidget

where ListObject is composed of NetFrame's and NetFrame is composed of
NetWidget's.
This commit is contained in:
lunar-mining
2022-03-13 13:25:55 +01:00
parent 4bcf0024b3
commit 2b408b5d88
2 changed files with 241 additions and 125 deletions

View File

@@ -152,12 +152,14 @@ async fn poll(client: Map, model: Arc<Model>) -> Result<()> {
let reply = client.get_info().await?;
if reply.as_object().is_some() && !reply.as_object().unwrap().is_empty() {
debug!("reply: {:?}", reply);
// TODO: we are ignoring this value for now
let _ext_addr = reply.as_object().unwrap().get("external_addr");
let inbound_obj = &reply.as_object().unwrap()["session_inbound"];
let manual_obj = &reply.as_object().unwrap()["session_manual"];
let outbound_obj = &reply.as_object().unwrap()["session_outbound"];
//debug!("OOBJ {:?}", outbound_obj);
let mut iconnects = Vec::new();
let mut mconnects = Vec::new();
@@ -168,7 +170,7 @@ async fn poll(client: Map, model: Arc<Model>) -> Result<()> {
let i_connected = &inbound_obj["connected"];
if i_connected.as_object().unwrap().is_empty() {
// channel is empty. initialize with empty values
let connected = "Null".to_string();
let connected = "Empty".to_string();
let msg = "Null".to_string();
let status = "Null".to_string();
let channel = Channel::new(msg, status);

View File

@@ -1,88 +1,204 @@
use crate::view::View;
//use log::debug;
use tui::{
backend::Backend,
layout::{Alignment, Constraint, Direction, Layout, Rect},
layout::{Alignment, Constraint, Direction, Layout},
style::Style,
text::{Span, Spans},
widgets::{Block, Borders, List, ListItem, Paragraph},
Frame,
};
pub fn ui<B: Backend>(f: &mut Frame<'_, B>, mut view: View) {
let slice = Layout::default()
.direction(Direction::Horizontal)
.margin(2)
.constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref())
.split(f.size());
pub fn make_oframe() -> NetFrame {
let ot_len = 4;
let ot_width = 8;
let ot_align = Alignment::Left;
let ot_cnstrnt = vec![Constraint::Percentage(100)];
let ot_widget = NetWidget::new(ot_len, ot_width, ot_align, ot_cnstrnt);
let nodes: Vec<ListItem> = view
.id_list
.node_id
.iter()
.map(|id| {
let lines = vec![Spans::from(id.to_string())];
ListItem::new(lines).style(Style::default())
})
.collect();
// create outbound msg widget
let om_len = 5;
let om_width = 8;
let om_align = Alignment::Right;
let om_cnstrnt = vec![Constraint::Percentage(45), Constraint::Percentage(55)];
let om_widget = NetWidget::new(om_len, om_width, om_align, om_cnstrnt);
let nodes =
List::new(nodes).block(Block::default().borders(Borders::ALL)).highlight_symbol(">> ");
// create outbound slot widget
let os_len = 5;
let os_width = 10;
let os_align = Alignment::Left;
let os_cnstrnt = vec![Constraint::Percentage(45), Constraint::Percentage(55)];
let os_widget = NetWidget::new(os_len, os_width, os_align, os_cnstrnt);
f.render_stateful_widget(nodes, slice[0], &mut view.id_list.state);
let index = view.info_list.index;
render_info_left(view.clone(), f);
render_info_right(view.clone(), f, index, slice);
// get total size
let oframe = NetFrame::new(ot_widget, os_widget, om_widget);
oframe
}
fn render_info_left<B: Backend>(view: View, f: &mut Frame<'_, B>) {
let len = draw_outbound(view.clone(), f);
let len = draw_inbound(view.clone(), f, len);
draw_manual(view.clone(), f, len);
pub fn make_iframe(oframe: NetFrame) -> NetFrame {
// create inbound title widget
let it_len = oframe.addrs.len;
let it_width = 8;
let it_align = Alignment::Left;
let it_cnstrnt = vec![Constraint::Percentage(100)];
let it_widget = NetWidget::new(it_len, it_width, it_align, it_cnstrnt);
// create inbound addr widget
let is_len = oframe.addrs.len + oframe.title.len + 1;
let is_width = 10;
let is_align = Alignment::Left;
let is_cnstrnt = vec![Constraint::Percentage(45), Constraint::Percentage(55)];
let is_widget = NetWidget::new(is_len, is_width, is_align, is_cnstrnt);
// create inbound msg widget
let im_len = is_len;
let im_width = 8;
let im_align = Alignment::Right;
let im_cnstrnt = vec![Constraint::Percentage(45), Constraint::Percentage(55)];
let im_widget = NetWidget::new(im_len, im_width, im_align, im_cnstrnt);
let iframe = NetFrame::new(it_widget, is_widget, im_widget);
iframe
}
// We're not doing anything here right now.
fn render_info_right<B: Backend>(
_view: View,
f: &mut Frame<'_, B>,
_index: usize,
slice: Vec<Rect>,
) {
let span = vec![];
let graph =
Paragraph::new(span).block(Block::default().borders(Borders::ALL)).style(Style::default());
f.render_widget(graph, slice[1]);
pub fn make_mframe(iframe: NetFrame) -> NetFrame {
let mt_len = iframe.title.len + iframe.addrs.len + 1;
let mt_width = 8;
let mt_align = Alignment::Left;
let mt_cnstrnt = vec![Constraint::Percentage(100)];
let mt_widget = NetWidget::new(mt_len, mt_width, mt_align, mt_cnstrnt);
// create manual data widget
let mk_len = mt_len + 1;
let mk_width = 10;
let mk_align = Alignment::Left;
let mk_cnstrnt = vec![Constraint::Percentage(45), Constraint::Percentage(55)];
let mk_widget = NetWidget::new(mk_len, mk_width, mk_align, mk_cnstrnt);
// create manual data widget
let mm_len = mt_len + 1;
let mm_width = 10;
let mm_align = Alignment::Left;
let mm_cnstrnt = vec![Constraint::Percentage(45), Constraint::Percentage(55)];
let mm_widget = NetWidget::new(mm_len, mm_width, mm_align, mm_cnstrnt);
let mframe = NetFrame::new(mt_widget.clone(), mk_widget.clone(), mm_widget);
mframe
}
fn draw_outbound<B: Backend>(view: View, f: &mut Frame<'_, B>) -> usize {
let t_len = 4;
let m_len = 4;
let s_len = 4;
pub fn ui<B: Backend>(f: &mut Frame<'_, B>, view: View) {
let oframe = make_oframe();
draw_outbound(f, view.clone(), oframe.clone());
let t_width = 8;
let m_width = 8;
let s_width = 10;
let iframe = make_iframe(oframe.clone());
draw_inbound(f, view.clone(), iframe.clone(), oframe.clone());
let t_align = Alignment::Left;
let m_align = Alignment::Right;
let s_align = Alignment::Left;
let mframe = make_mframe(iframe.clone());
draw_manual(f, view.clone(), mframe.clone());
let t_cnstrnt = vec![Constraint::Percentage(100)];
let m_cnstrnt = vec![Constraint::Percentage(45), Constraint::Percentage(55)];
let s_cnstrnt = vec![Constraint::Percentage(45), Constraint::Percentage(55)];
let top_widget = ListWidget::new(oframe, iframe, mframe);
let list_margin = 2;
let list_direction = Direction::Horizontal;
let list_cnstrnts = vec![Constraint::Percentage(50), Constraint::Percentage(50)];
let prev_len = top_widget.manual.addrs.len;
draw_list(list_margin, prev_len, list_direction, list_cnstrnts, view.clone(), f);
//render_info_right(view.clone(), f, slice);
}
//fn render_info_right<B: Backend>(_view: View, f: &mut Frame<'_, B>, slice: Vec<Rect>) {
// let span = vec![];
// let graph =
// Paragraph::new(span).block(Block::default().borders(Borders::ALL)).style(Style::default());
// f.render_widget(graph, slice[1]);
//}
// Top level widget
#[derive(Clone)]
pub struct ListWidget {
pub outbound: NetFrame,
pub inbound: NetFrame,
pub manual: NetFrame,
}
impl ListWidget {
pub fn new(outbound: NetFrame, inbound: NetFrame, manual: NetFrame) -> ListWidget {
ListWidget { outbound, inbound, manual }
}
}
// Middle level widgets
#[derive(Clone)]
pub struct NetFrame {
pub title: NetWidget,
pub addrs: NetWidget,
pub msgs: NetWidget,
}
impl NetFrame {
pub fn new(title: NetWidget, addrs: NetWidget, msgs: NetWidget) -> NetFrame {
NetFrame { title, addrs, msgs }
}
pub fn get_total_len(self) -> usize {
let t_len = self.title.len;
let a_len = self.addrs.len;
let m_len = self.msgs.len;
let total_len = t_len + a_len + m_len;
total_len
}
}
// Lowest level widgets
#[derive(Clone)]
pub struct NetWidget {
pub len: usize,
pub width: usize,
pub align: Alignment,
pub cnstrnts: Vec<Constraint>,
}
impl NetWidget {
pub fn new(len: usize, width: usize, align: Alignment, cnstrnts: Vec<Constraint>) -> NetWidget {
NetWidget { len, width, align, cnstrnts }
}
pub fn update(mut self, len: usize) {
self.len = len
}
pub fn draw<B: Backend>(self, vec: Vec<Spans>, f: &mut Frame<'_, B>) {
let slice = Layout::default()
.direction(Direction::Horizontal)
.horizontal_margin(self.width as u16)
.vertical_margin(self.len as u16)
.constraints(self.cnstrnts.as_ref())
.split(f.size());
let graph = Paragraph::new(vec).style(Style::default()).alignment(self.align);
f.render_widget(graph, slice[0]);
}
pub fn get_len(self) -> usize {
return self.len;
}
}
fn draw_outbound<B: Backend>(f: &mut Frame<'_, B>, view: View, oframe: NetFrame) {
let mut titles = Vec::new();
let mut msgs = Vec::new();
let mut slots = Vec::new();
titles.push(Spans::from(Span::styled("Outgoing", Style::default())));
for id in &view.id_list.node_id {
match &view.info_list.infos.get(id) {
Some(connects) => {
titles.push(Spans::from(Span::styled("Outbound:", Style::default())));
// there is only a single outbound connection so this works
for slot in &connects.outbound[0].slots {
slots.push(Spans::from(format!("{}", slot.addr)));
if slot.addr.is_empty() {
slots.push(Spans::from(format!("Empty")));
} else {
slots.push(Spans::from(format!("{}", slot.addr)));
}
match slot.channel.last_status.as_str() {
"recv" => {
msgs.push(Spans::from(format!("[R: {}]", slot.channel.last_msg)));
@@ -102,44 +218,40 @@ fn draw_outbound<B: Backend>(view: View, f: &mut Frame<'_, B>) -> usize {
}
}
let s_len = s_len + titles.len() as u16;
let m_len = m_len + titles.len() as u16;
oframe.title.clone().draw(titles.clone(), f);
let t_len2 = titles.clone().len();
oframe.title.clone().update(t_len2);
draw(t_len, t_width, titles, t_align, t_cnstrnt, f);
draw(s_len, s_width, slots, s_align, s_cnstrnt, f);
draw(m_len, m_width, msgs, m_align, m_cnstrnt, f);
oframe.addrs.clone().draw(slots.clone(), f);
let s_len2 = slots.clone().len();
oframe.addrs.clone().update(s_len2);
let total_len = t_len as usize + s_len as usize;
total_len
oframe.msgs.clone().draw(msgs.clone(), f);
let m_len2 = msgs.clone().len();
oframe.msgs.clone().update(m_len2);
}
fn draw_inbound<B: Backend>(view: View, f: &mut Frame<'_, B>, len: usize) -> usize {
let t_len = len as u16;
let a_len = len as u16;
let m_len = len as u16;
let t_width = 8;
let a_width = 10;
let m_width = 10;
let t_align = Alignment::Left;
let m_align = Alignment::Right;
let a_align = Alignment::Left;
let t_cnstrnt = vec![Constraint::Percentage(100)];
let a_cnstrnt = vec![Constraint::Percentage(45), Constraint::Percentage(55)];
let m_cnstrnt = vec![Constraint::Percentage(45), Constraint::Percentage(55)];
fn draw_inbound<B: Backend>(
f: &mut Frame<'_, B>,
view: View,
iframe: NetFrame,
outframe: NetFrame,
) {
let slots_len = outframe.addrs.get_len();
let mut titles = Vec::new();
let mut addrs = Vec::new();
let mut msgs = Vec::new();
// need to have access to slots_len
for _i in 1..slots_len {
titles.push(Spans::from(""));
}
titles.push(Spans::from(Span::styled("Incoming", Style::default())));
for id in &view.id_list.node_id {
match &view.info_list.infos.get(id) {
Some(connection) => {
if !connection.inbound.is_empty() {
for connect in &connection.inbound {
addrs.push(Spans::from(""));
addrs.push(Spans::from(connect.connected.clone()));
match connect.channel.last_status.as_str() {
"recv" => {
@@ -157,16 +269,12 @@ fn draw_inbound<B: Backend>(view: View, f: &mut Frame<'_, B>, len: usize) -> usi
)));
}
_ => {
// TODO: handle these values
// Do nothing for now
}
}
}
} else {
// Inbound connection is empty. Render empty data
titles.push(Spans::from(Span::styled("Inbound:", Style::default())));
addrs.push(Spans::from("Null"));
msgs.push(Spans::from("[R: Null]"));
msgs.push(Spans::from("[S: Null]"));
// Do nothing for now
}
}
None => {
@@ -175,40 +283,30 @@ fn draw_inbound<B: Backend>(view: View, f: &mut Frame<'_, B>, len: usize) -> usi
}
}
let a_len = a_len + titles.len() as u16;
let m_len = m_len + titles.len() as u16;
iframe.title.clone().draw(titles.clone(), f);
let t_len2 = titles.clone().len();
iframe.title.clone().update(t_len2);
draw(t_len, t_width, titles, t_align, t_cnstrnt, f);
draw(a_len, a_width, addrs, a_align, a_cnstrnt, f);
draw(m_len, m_width, msgs, m_align, m_cnstrnt, f);
iframe.addrs.clone().draw(addrs.clone(), f);
let s_len2 = addrs.clone().len();
iframe.addrs.clone().update(s_len2);
let total_len = t_len as usize + a_len as usize;
total_len
iframe.msgs.clone().draw(msgs.clone(), f);
let m_len2 = msgs.clone().len();
iframe.msgs.clone().update(m_len2);
}
fn draw_manual<B: Backend>(view: View, f: &mut Frame<'_, B>, len: usize) {
let t_len = len as u16;
let k_len = len as u16;
let t_width = 8;
let k_width = 10;
let t_align = Alignment::Left;
let k_align = Alignment::Left;
let t_cnstrnt = vec![Constraint::Percentage(100)];
let k_cnstrnt = vec![Constraint::Percentage(45), Constraint::Percentage(55)];
fn draw_manual<B: Backend>(f: &mut Frame<'_, B>, view: View, mframe: NetFrame) {
let mut titles = Vec::new();
let mut keys = Vec::new();
titles.push(Spans::from(Span::styled("Manual", Style::default())));
for id in &view.id_list.node_id {
match &view.info_list.infos.get(id) {
Some(connects) => {
titles.push(Spans::from(Span::styled("Manual:", Style::default())));
keys.push(Spans::from(""));
keys.push(Spans::from(format!("Key: {}", connects.manual[0].key)));
keys.push(Spans::from(""));
for _conn in &connects.manual {
keys.push(Spans::from(format!("{}", connects.manual[0].key)));
}
}
None => {
// TODO
@@ -216,24 +314,40 @@ fn draw_manual<B: Backend>(view: View, f: &mut Frame<'_, B>, len: usize) {
}
}
draw(t_len, t_width, titles, t_align, t_cnstrnt, f);
draw(k_len, k_width, keys, k_align, k_cnstrnt, f);
mframe.title.clone().draw(titles.clone(), f);
let t_len2 = titles.clone().len();
mframe.title.clone().update(t_len2);
mframe.addrs.clone().draw(keys.clone(), f);
let s_len2 = keys.clone().len();
mframe.addrs.clone().update(s_len2);
}
fn draw<B: Backend>(
length: u16,
width: u16,
vec: Vec<Spans>,
align: Alignment,
fn draw_list<B: Backend>(
margin: u16,
prev_len: usize,
direction: Direction,
cnstrnts: Vec<Constraint>,
mut view: View,
f: &mut Frame<'_, B>,
) {
let slice = Layout::default()
.direction(Direction::Horizontal)
.horizontal_margin(width)
.vertical_margin(length)
.constraints(cnstrnts.as_ref())
.split(f.size());
let graph = Paragraph::new(vec).style(Style::default()).alignment(align);
f.render_widget(graph, slice[0]);
let mut nodes = Vec::new();
for id in &view.id_list.node_id {
let mut lines = vec![Spans::from(id.to_string())];
// need total_len
for _i in 1..prev_len {
lines.push(Spans::from(""));
}
let ids = ListItem::new(lines).style(Style::default());
nodes.push(ids)
}
let nodes =
List::new(nodes).block(Block::default().borders(Borders::ALL)).highlight_symbol(">> ");
// this is just the box around the list. not the actual list
let slice =
Layout::default().direction(direction).margin(margin).constraints(cnstrnts).split(f.size());
f.render_stateful_widget(nodes, slice[0], &mut view.id_list.state);
}