Skip to content

Commit

Permalink
Add time formatting
Browse files Browse the repository at this point in the history
  • Loading branch information
Zerthox committed Dec 27, 2024
1 parent 5e78de3 commit 00cacfc
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 39 deletions.
4 changes: 2 additions & 2 deletions reffect/src/elements/text/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ mod props;
use super::{align::AlignHorizontal, Props, RenderState};
use crate::{
context::{Context, ContextUpdate},
fmt::Pretty,
fmt::Unit,
render::{Bounds, ComponentWise, Render, RenderDebug, RenderOptions},
render_util::{
debug_optional, draw_text_bg, helper, input_text_multi_with_menu, LoadedFont, Rect,
Expand Down Expand Up @@ -78,7 +78,7 @@ impl Text {
}
'I' => {
iter.next();
result.push_str(&Pretty(active.intensity()).to_string());
result.push_str(&Unit::format(active.intensity()));
}
'c' | 'r' => {
iter.next();
Expand Down
95 changes: 72 additions & 23 deletions reffect/src/fmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,44 +2,86 @@ use std::fmt;

#[derive(Debug, Clone, Copy)]
#[repr(transparent)]
pub struct Pretty<T>(pub T);

impl<T> Pretty<T> {
const KILO: f32 = 1_000.0;
pub struct Time(pub u32);

impl Time {
pub const SEC: u32 = 1000;
pub const MIN: u32 = 60 * Self::SEC;

#[allow(unused)]
pub const fn new(min: u32, sec: u32, ms: u32) -> Self {
Self(Self::MIN * min + Self::SEC * sec + ms)
}

pub fn format(value: u32) -> String {
Self(value).to_string()
}
}

impl fmt::Display for Time {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let value = self.0;
let min = value / Self::MIN;
let secs = (value % Self::MIN) as f32 / Self::SEC as f32;
if min > 0 {
write!(f, "{min}:{secs:0>4.1}")
} else {
write!(f, "{secs:.1}")
}
}
}

#[derive(Debug, Clone, Copy)]
#[repr(transparent)]
pub struct Unit<T>(pub T);

impl<T> Unit<T> {
const KILO: f32 = 1_000.0;
const MEGA: f32 = 1_000_000.0;
const GIGA: f32 = 1_000_000_000.0;

pub fn format(value: T) -> String
where
Self: fmt::Display,
{
Self(value).to_string()
}

pub fn string_if(value: T, pretty: bool) -> String
pub fn format_if(value: T, unit: bool) -> String
where
T: fmt::Display,
Pretty<T>: fmt::Display,
Self: fmt::Display,
{
if pretty {
Self(value).to_string()
if unit {
Self::format(value)
} else {
value.to_string()
}
}
}

impl fmt::Display for Pretty<f32> {
impl fmt::Display for Unit<f32> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let value = self.0;
match value {
Self::GIGA.. => write!(f, "{:.2}B", value / Self::GIGA),
Self::MEGA.. => write!(f, "{:.2}M", value / Self::MEGA),
Self::KILO.. => write!(f, "{:.1}k", value / Self::KILO),
_ => write!(f, "{value:.1}"),
}
}
}

impl fmt::Display for Pretty<u32> {
impl fmt::Display for Unit<u32> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
const MEGA: u32 = Pretty::<u32>::MEGA as u32;
const KILO: u32 = Pretty::<u32>::KILO as u32;
const KILO: u32 = Unit::<u32>::KILO as u32;
const MEGA: u32 = Unit::<u32>::MEGA as u32;
const GIGA: u32 = Unit::<u32>::GIGA as u32;

let value = self.0;
match value {
GIGA.. => write!(f, "{:.2}B", value as f32 / Self::GIGA),
MEGA.. => write!(f, "{:.2}M", value as f32 / Self::MEGA),
KILO.. => write!(f, "{:.1}k", value as f32 / Self::KILO),
_ => write!(f, "{value}"),
Expand All @@ -52,20 +94,27 @@ mod tests {
use super::*;

#[test]
fn u32() {
assert_eq!(Pretty(0).to_string(), "0");
assert_eq!(Pretty(123).to_string(), "123");
assert_eq!(Pretty(1_000).to_string(), "1.0k");
assert_eq!(Pretty(76_590).to_string(), "76.6k");
assert_eq!(Pretty(1_239_000).to_string(), "1.24M");
fn time() {
assert_eq!(Time::format(0), "0.0");
assert_eq!(Time::format(1234), "1.2");
assert_eq!(Time::new(3, 4, 567).to_string(), "3:04.6");
}

#[test]
fn unit_u32() {
assert_eq!(Unit::format(0), "0");
assert_eq!(Unit::format(123), "123");
assert_eq!(Unit::format(1_000), "1.0k");
assert_eq!(Unit::format(76_590), "76.6k");
assert_eq!(Unit::format(1_239_000), "1.24M");
}

#[test]
fn f32() {
assert_eq!(Pretty(0.0).to_string(), "0.0");
assert_eq!(Pretty(123.49).to_string(), "123.5");
assert_eq!(Pretty(1_000.0).to_string(), "1.0k");
assert_eq!(Pretty(76_590.0).to_string(), "76.6k");
assert_eq!(Pretty(1_239_000.0).to_string(), "1.24M");
fn unit_f32() {
assert_eq!(Unit::format(0.0), "0.0");
assert_eq!(Unit::format(123.49), "123.5");
assert_eq!(Unit::format(1_000.0), "1.0k");
assert_eq!(Unit::format(76_590.0), "76.6k");
assert_eq!(Unit::format(1_239_000.0), "1.24M");
}
}
2 changes: 1 addition & 1 deletion reffect/src/settings/icon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ impl StackTextSettings {
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(default)]
pub struct DurationTextSettings {
pub max_remain: u32,
pub max_remain: u32, // TODO: different for buff & ability
pub scale: f32,
pub color: [f32; 4],
pub color_fast: [f32; 4],
Expand Down
20 changes: 8 additions & 12 deletions reffect/src/trigger/progress/active.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::{
fmt::Pretty,
fmt::{Time, Unit},
internal::{Ability, Buff, Recharge, Resource, Skillbar},
};

Expand Down Expand Up @@ -209,9 +209,9 @@ impl ProgressActive {
}

/// Returns the current amount as text.
pub fn current_text(&self, value: ProgressValue, now: u32, pretty: bool) -> String {
pub fn current_text(&self, value: ProgressValue, now: u32, unit: bool) -> String {
match *self {
Self::Fixed { current, .. } => Pretty::string_if(current, pretty),
Self::Fixed { current, .. } => Unit::format_if(current, unit),
Self::Buff { end, .. } => {
if end == u32::MAX {
"?".into()
Expand Down Expand Up @@ -246,12 +246,12 @@ impl ProgressActive {
}

/// Returns the maximum amount as text.
pub fn max_text(&self, value: ProgressValue, pretty: bool) -> String {
pub fn max_text(&self, value: ProgressValue, unit: bool) -> String {
match *self {
Self::Fixed { max, .. } => Pretty::string_if(max, pretty),
Self::Fixed { max, .. } => Unit::format_if(max, unit),
Self::Buff { duration, .. } => {
if duration != u32::MAX {
Self::format_seconds(duration)
Time::format(duration)
} else {
"?".into()
}
Expand All @@ -260,7 +260,7 @@ impl ProgressActive {
recharge,
ammo_recharge,
..
} => Self::format_seconds(value.pick(recharge, ammo_recharge)),
} => Time::format(value.pick(recharge, ammo_recharge)),
}
}

Expand All @@ -276,13 +276,9 @@ impl ProgressActive {
(time as f32 / rate) as u32
}

fn format_seconds(time: u32) -> String {
format!("{:.1}", time as f32 / 1000.0)
}

fn duration_text(time: u32) -> String {
if time > 0 {
Self::format_seconds(time)
Time::format(time)
} else {
String::new()
}
Expand Down
2 changes: 1 addition & 1 deletion reffect/src/trigger/progress/source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ impl RenderOptions for ProgressSource {
_ => {}
}
}
helper(ui, || ui.text("Source of information"));
helper(ui, || ui.text("Source of information")); // TODO: mention inherit being passed down, not affecting group visibility

match self {
Self::Buff(id) => {
Expand Down

0 comments on commit 00cacfc

Please sign in to comment.