1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
extern crate std;
use std::collections::HashMap;
use std::convert::TryFrom;
use std::thread::ThreadId;

extern crate tui;
use tui::{Terminal, Frame};
use tui::backend::Backend;
use tui::layout::{Alignment, Rect};
use tui::widgets::{Block, Borders, Paragraph};

use crate::userinterface::views::ratio;
use crate::userinterface::widgets::{BORDERS, EMPTY_SPACES, gauge::{self, Rgb}};

const EXTRA_SPACES: u16 = 3;
const LARGER_ROW: u16 = 29;

pub const WIN_WIDTH: u16 = LARGER_ROW + (EMPTY_SPACES + EXTRA_SPACES) * 2
  + BORDERS;

const TEXT_HEIGHT: u16 = 2;
const GAUGE_NUMBERS: u16 = 4;
pub const MAX_WIN_HEIGHT: u16 = EMPTY_SPACES + BORDERS + TEXT_HEIGHT +
  gauge::GAUGE_HEIGHT * (GAUGE_NUMBERS + 1);

pub fn render<B: Backend>(terminal: &mut Terminal<B>,
  threads: &HashMap<ThreadId, (u16, u16)>, tasks: (usize, usize)) {
    terminal.draw(|frame| {
      let frame_area = frame.size();

      let frame_left = frame_area.left();
      let frame_top = frame_area.top();
      let frame_width = frame_area.right() - frame_left;
      let frame_height = frame_area.bottom() - frame_top;

      let window_height = EMPTY_SPACES + BORDERS + TEXT_HEIGHT +
        gauge::GAUGE_HEIGHT * u16::try_from(threads.len() + 1).unwrap();
      let window_area = Rect::new(frame_left + frame_width/2 - WIN_WIDTH/2,
        frame_top + frame_height/2 - window_height/2, WIN_WIDTH, window_height);
      let window_left = window_area.left();
      let window_top = window_area.top();
      let window_width = window_area.right() - window_left;

      let inner_area = Rect::new(window_left + 1, window_top + 2,
        window_width - BORDERS, window_height - BORDERS);

      render_borders(frame, &window_area);
      render_text(frame, &inner_area);
      render_gauges(frame, &inner_area, threads, tasks);

    }).unwrap();
}

fn render_borders<B: Backend>(frame: &mut Frame<B>, area: &Rect) {
  let block = Block::default().borders(Borders::ALL);
  frame.render_widget(block, *area);
}

fn render_text<B: Backend>(frame: &mut Frame<B>, area: &Rect) {
  let paragraph = Paragraph::new("Liriodendron have to complete
tasks before to exit").alignment(Alignment::Center);

  frame.render_widget(paragraph, *area);
}

fn render_gauges<B: Backend>(frame: &mut Frame<B>, area: &Rect,
  threads: &HashMap<ThreadId, (u16, u16)>,
  (tasks_done, tasks_todo): (usize, usize)) {

    let mut gauge_label = format!("Tasks: {}/{}", tasks_done, tasks_todo);
    let mut gauge_ratio = ratio(tasks_done, tasks_todo);
    let mut area = Rect::new(area.left(), area.top() + gauge::GAUGE_HEIGHT,
      area.right() - area.left(), gauge::GAUGE_HEIGHT);
    if gauge_ratio < 0.5 {
      frame.render_widget(gauge::GaugeWidget::new( gauge_ratio, &gauge_label,
        (Rgb::RED, Rgb::YELLOW, gauge_ratio * 2.)), area);
    } else {
      frame.render_widget(gauge::GaugeWidget::new(gauge_ratio, &gauge_label,
        (Rgb::YELLOW, Rgb::GREEN, (gauge_ratio - 0.5) * 2.)), area);
    }

    let mut id = 1;
    for (_, &(gen_done, gen_todo)) in threads.iter() {
      area = Rect::new(area.left(), area.top() + gauge::GAUGE_HEIGHT,
        area.right() - area.left(), gauge::GAUGE_HEIGHT);
      gauge_label = format!("Process {}: {}/{}", id, gen_done, gen_todo);
      gauge_ratio = ratio(gen_done, gen_todo);
      if gauge_ratio < 0.5 {
        frame.render_widget(gauge::GaugeWidget::new(gauge_ratio, &gauge_label,
          (Rgb::RED, Rgb::YELLOW, gauge_ratio * 2.)), area);
      } else {
        frame.render_widget(gauge::GaugeWidget::new(gauge_ratio, &gauge_label,
          (Rgb::YELLOW, Rgb::GREEN, (gauge_ratio - 0.5) * 2.)), area);
      }
      id += 1;
    }
}