diff --git a/Cargo.lock b/Cargo.lock index 3ca25a4..1633467 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -702,7 +702,7 @@ checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" [[package]] name = "frametap" -version = "0.1.0" +version = "0.1.2" dependencies = [ "bitflags 2.13.2", "eframe", diff --git a/Cargo.toml b/Cargo.toml index 29c374f..db21efe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "frametap" -version = "0.1.0" +version = "0.1.2" edition = "2021" [dependencies] diff --git a/src/ui.rs b/src/ui.rs index 41ed1fc..aef8b59 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -23,6 +23,10 @@ pub const DEFAULT_TRIALS_SHOWN: usize = 5; /// 離した区間を行にするかの既定値。 pub const DEFAULT_SHOW_RELEASED: bool = false; +/// 画面に出す版。実機から返ってくるのは写真なので、どの build を動かしたのかを +/// 写真だけで決められるようにする。問い合わせを 1 往復減らす。 +pub const VERSION: &str = env!("CARGO_PKG_VERSION"); + /// 持続 F をそのまま出す上限。これを超えたら [`HOLD_OVERFLOW_TEXT`] にする。 /// 押しっぱなしの行が桁を増やすと、右端の列幅が動いて他の行の数字が読みにくくなる。 const HOLD_FRAMES_CAP: f64 = 99.0; @@ -213,16 +217,16 @@ pub fn show( /// 但し書きは条件付きで隠さない。1F ずれを読んでいる最中に、表示の幅が /// どこから来ているかを思い出せる状態にしておく。 fn show_header(ui: &mut Ui, status: &Status, settings: &Settings, notices: &[String]) { - match &status.device_name { - Some(name) => ui.label(format!("connected: {name}")), - None => ui.label( - RichText::new(match &status.disconnected_reason { - Some(reason) => format!("disconnected: {reason}"), - None => "disconnected".to_owned(), - }) - .color(Color32::LIGHT_RED), - ), - }; + // 版と接続を同じ行に置く。窓は縦に狭く、但し書きだけで数行を使う。 + ui.horizontal(|ui| { + ui.label(title_text()); + + let text = RichText::new(status_text(status)); + match status.device_name { + Some(_) => ui.label(text), + None => ui.label(text.color(Color32::LIGHT_RED)), + }; + }); match status.scale_us_per_tick { Some(scale) => ui.label(format!("device clock: {scale:.4} us/tick")), @@ -294,6 +298,20 @@ fn columns(names: &str, press: &str, hold: &str) -> String { format!("{names:FRAMES_WIDTH$}{hold:>FRAMES_WIDTH$}") } +/// 画面の左上に出す名前と版。 +pub fn title_text() -> String { + format!("frametap {VERSION}") +} + +/// 接続の状態を 1 行にする。 +pub fn status_text(status: &Status) -> String { + match (&status.device_name, &status.disconnected_reason) { + (Some(name), _) => format!("connected: {name}"), + (None, Some(reason)) => format!("disconnected: {reason}"), + (None, None) => "disconnected".to_owned(), + } +} + /// 押下 F の表示。押されていない区間では空欄にする。 pub fn press_text(frames: Option) -> String { match frames { diff --git a/tests/ui.rs b/tests/ui.rs index 660e049..80322b2 100644 --- a/tests/ui.rs +++ b/tests/ui.rs @@ -7,8 +7,8 @@ use frametap::history::{History, DEFAULT_RETAIN_US, DEFAULT_TRIAL_GAP_US}; use frametap::report_decode::{Buttons, Direction}; use frametap::timeline::{EventKind, InputEvent, Target}; use frametap::ui::{ - hold_text, lines, press_text, recent_trials, row_text, show, Settings, Status, - DEFAULT_TRIALS_SHOWN, HOLD_OVERFLOW_TEXT, + hold_text, lines, press_text, recent_trials, row_text, show, status_text, title_text, Settings, + Status, DEFAULT_TRIALS_SHOWN, HOLD_OVERFLOW_TEXT, }; /// 60fps の 1F。 @@ -290,6 +290,29 @@ fn a_new_connection_starts_without_a_scale() { assert_eq!(disconnected.scale_warning, None); } +/// 写真が返ってきたときに、どの build を動かしたのかを写真だけで決められる。 +#[test] +fn the_title_carries_the_crate_version() { + let title = title_text(); + + assert!(title.starts_with("frametap "), "{title}"); + assert!(title.contains(env!("CARGO_PKG_VERSION")), "{title}"); +} + +#[test] +fn the_status_line_names_the_device_or_the_reason() { + assert_eq!( + status_text(&Status::connected("DualSense".to_owned())), + "connected: DualSense" + ); + assert_eq!( + status_text(&Status::disconnected("read failed".to_owned())), + "disconnected: read failed" + ); + // 理由が無いのは起動直後だけになる。 + assert_eq!(status_text(&Status::default()), "disconnected"); +} + /// 描画がウィンドウ無しで最後まで通る。列の確保と幅の計算が壊れていれば panic する。 #[test] fn show_runs_without_a_window() {