From 2a0a8abd60bef22c9175fe82ea35f84d6bff36cb Mon Sep 17 00:00:00 2001 From: Ultradesu Date: Fri, 2 Oct 2026 16:04:39 +0100 Subject: [PATCH] Tray: split rate/plot columns, add unit toggle to the devices window MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The connected-peers rate and sparkline shared one grid cell, so the plot still moved right as the rate text grew (e.g. "1.0 kB/s"). They are now two separate grid columns — the plot column starts at the same x on every row, since grid columns align. The devices window also gets its own pkts/bytes toggle, bound to the same unit setting as the main window so the two stay in step. Builds and is clippy-clean (-D warnings) on macOS; not run in this headless session. Co-Authored-By: Claude Opus 4.8 --- crates/tsunagi-tray/src/app.rs | 4 +++- crates/tsunagi-tray/src/devices.rs | 33 ++++++++++++++++++------------ 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/crates/tsunagi-tray/src/app.rs b/crates/tsunagi-tray/src/app.rs index 8364363..2200c10 100644 --- a/crates/tsunagi-tray/src/app.rs +++ b/crates/tsunagi-tray/src/app.rs @@ -99,7 +99,6 @@ impl App { let Some(Ok(report)) = &snapshot.status else { return; }; - let unit = self.state.unit; let open: Vec = self.state.open_devices.iter().cloned().collect(); for id in open { let Some(network) = report.networks.iter().find(|n| n.network_id == id) else { @@ -114,6 +113,9 @@ impl App { .with_min_inner_size([480.0, 320.0]); let agent = &self.agent; let traffic = &self.traffic; + // The window shares the single unit setting, so its toggle and the + // main window's stay in step. + let unit = &mut self.state.unit; let keep = ctx.show_viewport_immediate(viewport_id, builder, |vctx, _class| { devices::show(vctx, agent, unit, network, traffic); !vctx.input(|i| i.viewport().close_requested()) diff --git a/crates/tsunagi-tray/src/devices.rs b/crates/tsunagi-tray/src/devices.rs index eb64e7e..a1ff3cb 100644 --- a/crates/tsunagi-tray/src/devices.rs +++ b/crates/tsunagi-tray/src/devices.rs @@ -24,12 +24,21 @@ pub(crate) fn title(network: &NetworkReport) -> String { pub(crate) fn show( ctx: &egui::Context, _agent: &AgentClient, - unit: Unit, + unit: &mut Unit, network: &NetworkReport, traffic: &Traffic, ) { egui::CentralPanel::default().show(ctx, |ui| { - ui.heading(&network.name); + ui.horizontal(|ui| { + ui.heading(&network.name); + ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| { + ui.selectable_value(unit, Unit::Bytes, "bytes"); + ui.selectable_value(unit, Unit::Packets, "pkts"); + ui.label("show:"); + }); + }); + // A copy of the chosen unit for the read-only rendering below. + let unit = *unit; summary(ui, network); ui.add_space(6.0); @@ -129,7 +138,7 @@ fn connected_table( return; } egui::Grid::new("connected") - .num_columns(7) + .num_columns(8) .striped(true) .spacing([10.0, 4.0]) .show(ui, |ui| { @@ -140,7 +149,8 @@ fn connected_table( "handshake", "pkts", "bytes", - "rate / plot", + "rate", + "plot", ] { ui.weak(header); } @@ -169,15 +179,12 @@ fn connected_table( format::bytes(peer.rx_bytes as f64) )); let series = traffic.peer(network_id, &peer.public_key); - ui.horizontal(|ui| { - // A fixed-width rate so the inline plot does not shift as - // the number's length changes (e.g. "0 B/s" vs "1.1 kB/s"). - ui.allocate_ui(egui::vec2(64.0, 18.0), |ui| { - ui.add(egui::Label::new(format::series_rate(series, unit)).truncate()); - }); - ui.allocate_ui(egui::vec2(90.0, 20.0), |ui| { - format::sparkline(ui, series, unit, 18.0); - }); + // Rate and plot are separate grid columns, so the plot column + // starts at the same x on every row regardless of the rate's + // text width. + ui.add(egui::Label::new(format::series_rate(series, unit)).truncate()); + ui.allocate_ui(egui::vec2(100.0, 20.0), |ui| { + format::sparkline(ui, series, unit, 18.0); }); ui.end_row(); }