From 2b408b5d888e1f9e6952bfdf213c63e6bab78aa5 Mon Sep 17 00:00:00 2001 From: lunar-mining Date: Sun, 13 Mar 2022 13:25:55 +0100 Subject: [PATCH] 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. --- bin/dnetview/src/main.rs | 4 +- bin/dnetview/src/ui.rs | 362 +++++++++++++++++++++++++-------------- 2 files changed, 241 insertions(+), 125 deletions(-) diff --git a/bin/dnetview/src/main.rs b/bin/dnetview/src/main.rs index 3403a2739..26b80c63e 100644 --- a/bin/dnetview/src/main.rs +++ b/bin/dnetview/src/main.rs @@ -152,12 +152,14 @@ async fn poll(client: Map, model: Arc) -> 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) -> 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); diff --git a/bin/dnetview/src/ui.rs b/bin/dnetview/src/ui.rs index 06ef41d03..485d73515 100644 --- a/bin/dnetview/src/ui.rs +++ b/bin/dnetview/src/ui.rs @@ -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(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 = 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(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( - _view: View, - f: &mut Frame<'_, B>, - _index: usize, - slice: Vec, -) { - 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(view: View, f: &mut Frame<'_, B>) -> usize { - let t_len = 4; - let m_len = 4; - let s_len = 4; +pub fn ui(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(_view: View, f: &mut Frame<'_, B>, slice: Vec) { +// 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, +} + +impl NetWidget { + pub fn new(len: usize, width: usize, align: Alignment, cnstrnts: Vec) -> NetWidget { + NetWidget { len, width, align, cnstrnts } + } + + pub fn update(mut self, len: usize) { + self.len = len + } + + pub fn draw(self, vec: Vec, 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(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(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(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( + 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(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(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(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(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(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( - length: u16, - width: u16, - vec: Vec, - align: Alignment, +fn draw_list( + margin: u16, + prev_len: usize, + direction: Direction, cnstrnts: Vec, + 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); }