Parcourir la Source

Charts and size by type.

Eiyeron Fulmincendii il y a 2 ans
Parent
commit
da3bb80c11
6 fichiers modifiés avec 129 ajouts et 28 suppressions
  1. 1 1
      Cargo.lock
  2. 1 1
      Cargo.toml
  3. 11 2
      src/app.rs
  4. 21 5
      src/lumps.rs
  5. 2 2
      src/main.rs
  6. 93 17
      src/ui.rs

+ 1 - 1
Cargo.lock

@@ -366,7 +366,7 @@ dependencies = [
 ]
 
 [[package]]
-name = "wad-googles"
+name = "wad-goggles"
 version = "0.1.0"
 dependencies = [
  "crossterm",

+ 1 - 1
Cargo.toml

@@ -1,5 +1,5 @@
 [package]
-name = "wad-googles"
+name = "wad-goggles"
 version = "0.1.0"
 edition = "2021"
 

+ 11 - 2
src/app.rs

@@ -1,8 +1,8 @@
-use std::error;
+use std::{error, collections::HashMap};
 use ratatui::widgets::ListState;
 use wad::{Wad, load_wad_file};
 
-use crate::lumps::{LumpInfo, get_lumps};
+use crate::lumps::{LumpInfo, get_lumps, LumpType};
 
 /// Application result type.
 pub type AppResult<T> = std::result::Result<T, Box<dyn error::Error>>;
@@ -58,6 +58,7 @@ impl<T> StatefulList<T> {
 pub struct App {
     pub wad:Wad,
     pub lumps:StatefulList<LumpInfo>,
+    pub sizes: HashMap<Option<LumpType>, usize>,
     pub running:bool,
 }
 
@@ -65,9 +66,17 @@ impl App {
     fn from_wad(wad_path:&str) -> Self {
         let wad = load_wad_file(wad_path).unwrap();
         let lumps = get_lumps(&wad);
+        let mut sizes = HashMap::new();
+        for lump in lumps.iter() {
+            if let Some(LumpType::Marker(_, _)) = lump.lump_type {
+                continue;
+            }
+            sizes.insert(lump.lump_type.clone(), sizes.get(&lump.lump_type).unwrap_or(&0) + lump.size);
+        }
         Self {
             wad: wad,
             lumps: StatefulList::with_items(lumps),
+            sizes: sizes,
             running: true
         }
     }

+ 21 - 5
src/lumps.rs

@@ -1,9 +1,8 @@
-use std::marker;
+use std::fmt::Display;
 
-use ratatui::symbols::Marker;
 use wad::Wad;
 
-#[derive(PartialEq, Clone)]
+#[derive(Eq, PartialEq, Hash, Clone)]
 pub enum MarkerType {
     Flat,
     Sprite,
@@ -13,7 +12,7 @@ pub enum MarkerType {
     Unknown,
 }
 
-#[derive(PartialEq)]
+#[derive(Eq, PartialEq, Hash, Clone, Debug)]
 pub enum FileType {
     Map,
     Things,
@@ -34,7 +33,13 @@ pub enum FileType {
     Sfx,
 }
 
-#[derive(PartialEq)]
+impl Display for FileType {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "{:?}", self)
+    }
+}
+
+#[derive(Eq, PartialEq, Hash, Clone)]
 pub enum MarkerBoundary {
     Single,
     Begin,
@@ -42,11 +47,21 @@ pub enum MarkerBoundary {
     Unknown,
 }
 
+#[derive(Eq, PartialEq, Hash, Clone)]
 pub enum LumpType {
     Marker(MarkerType, MarkerBoundary),
     File(FileType),
 }
 
+impl LumpType {
+    pub fn to_ui_string(&self) -> String {
+        match self.clone() {
+            LumpType::File(file_type) => file_type.to_string(),
+            LumpType::Marker(_, _) => "- Marker -".into(),
+        }
+    }
+}
+
 pub struct LumpInfo {
     pub name: String,
     pub size: usize,
@@ -101,6 +116,7 @@ fn determine_lump_type(
 
 pub fn get_lumps(wad: &Wad) -> Vec<LumpInfo> {
     let mut current_marker_group: Option<MarkerType> = None;
+    // TODO 2-pass type detection.
     wad.as_slice()
         .entry_iter()
         .map(|entry| {

+ 2 - 2
src/main.rs

@@ -17,8 +17,8 @@ use std::io;
 fn get_wad_from_args() -> Result<String, &'static str> {
     let mut args: Vec<String> = env::args().collect();
 
-    if args.len() != 2 {
-        return Err("Too many arguments");
+    if args.len() < 2 {
+        return Err("Missing WAD argument.");
     }
     if let Some(path) = args.pop() {
         return Ok(path);

+ 93 - 17
src/ui.rs

@@ -1,5 +1,9 @@
+use std::cmp::max;
+use std::collections::hash_map::Iter;
+
+use ratatui::layout::{Constraint, Direction, Layout};
 use ratatui::text::Span;
-use ratatui::widgets::{List, ListItem};
+use ratatui::widgets::{BarChart, List, ListItem};
 use ratatui::{
     backend::Backend,
     layout::Alignment,
@@ -43,19 +47,8 @@ fn get_lump_style(lump: &LumpInfo) -> Style {
     style
 }
 
-/// Renders the user interface widgets.
-pub fn render<B: Backend>(app: &mut App, frame: &mut Frame<'_, B>) {
-    // This is where you add new widgets.
-    // See the following resources:
-    // - https://docs.rs/ratatui/latest/ratatui/widgets/index.html
-    // - https://github.com/tui-rs-revival/ratatui/tree/master/examples
-
-    let mut list_size = frame.size();
-    list_size.width = 18;
-
-    let items: Vec<ListItem> = app
-        .lumps
-        .items
+fn compute_lump_list(lumps: &[LumpInfo]) -> (Vec<ListItem>, u16) {
+    let lump_items: Vec<ListItem> = lumps
         .iter()
         .map(|lump| {
             ListItem::new(Line::from(Line::from(vec![
@@ -64,8 +57,53 @@ pub fn render<B: Backend>(app: &mut App, frame: &mut Frame<'_, B>) {
             ])))
         })
         .collect();
+    let item_width = 1 + lump_items
+        .iter()
+        .fold(0, |acc, item| max(acc, item.width() as u16));
+
+    (lump_items, item_width)
+}
+
+fn compute_size_list(sizes: Iter<'_, Option<LumpType>, usize>) -> (Vec<ListItem>, u16) {
+    let lump_items: Vec<ListItem> = sizes
+        .map(|(file_type, size)| {
+            let type_str = match file_type {
+                Some(file_type) => file_type.to_ui_string(),
+                None => "- Untyped -".into(),
+            };
+            ListItem::new(Line::from(Line::from(vec![
+                Span::styled(format!("{:16}", type_str), Style::default()),
+                Span::styled(format!("{:8}", size), Style::default()),
+            ])))
+        })
+        .collect();
+
+    let item_width = 1 + lump_items
+        .iter()
+        .fold(0, |acc, item| max(acc, item.width() as u16));
+
+    (lump_items, item_width)
+}
+
+/// Renders the user interface widgets.
+pub fn render<B: Backend>(app: &mut App, frame: &mut Frame<'_, B>) {
+    let (lump_items, item_width) = compute_lump_list(&app.lumps.items);
+
+    let (size_items, size_width) = compute_size_list(app.sizes.iter());
 
-    let list = List::new(items)
+    let chunks = Layout::default()
+        .direction(Direction::Horizontal)
+        .constraints(
+            [
+                Constraint::Length(item_width),
+                Constraint::Length(size_width),
+                Constraint::Ratio(1, 1),
+            ]
+            .as_ref(),
+        )
+        .split(frame.size());
+
+    let lump_list = List::new(lump_items)
         .block(
             Block::default()
                 .title("Files")
@@ -74,7 +112,45 @@ pub fn render<B: Backend>(app: &mut App, frame: &mut Frame<'_, B>) {
                 .border_type(BorderType::Plain),
         )
         .highlight_style(Style::default().bg(Color::Cyan))
-        .style(Style::default().fg(Color::Cyan).bg(Color::Black));
+        .style(Style::default());
+
+    let sizes_list = List::new(size_items)
+        .block(
+            Block::default()
+                .title("Sizes")
+                .title_alignment(Alignment::Center)
+                .borders(Borders::TOP | Borders::RIGHT)
+                .border_type(BorderType::Plain),
+        )
+        .highlight_style(Style::default().bg(Color::Cyan))
+        .style(Style::default());
+
+    let chart_data: Vec<(String, u64)> = app
+        .sizes
+        .iter()
+        .filter(|(_, size)| *size > &0)
+        .map(|(file_type, size)| {
+            let type_str = match file_type {
+                Some(file_type) => file_type.to_ui_string(),
+                None => "- Untyped -".into(),
+            };
+            (type_str, *size as u64)
+        })
+        .collect();
+    let char_slice: Vec<(&str, u64)> = chart_data
+        .iter()
+        .map(|(string, size)| (string.as_str(), *size))
+        .collect();
+
+    let size_chart = BarChart::default().data(&char_slice).bar_width(8).block(
+        Block::default()
+            .title("Sizes")
+            .title_alignment(Alignment::Center)
+            .borders(Borders::TOP | Borders::RIGHT)
+            .border_type(BorderType::Plain),
+    );
 
-    frame.render_stateful_widget(list, list_size, &mut app.lumps.state)
+    frame.render_stateful_widget(lump_list, chunks[0], &mut app.lumps.state);
+    frame.render_widget(sizes_list, chunks[1]);
+    frame.render_widget(size_chart, chunks[2]);
 }