mirror of
https://github.com/LGUG2Z/komorebi.git
synced 2026-07-11 23:52:47 +02:00
fix(bar): limit new state freq on time and date
This commit limits the number of times the time and date widgets get a new state. Even though having a limit of 1 second on the ui repaint, when the bar is focused or hovered, this is ignored and state of these widgets were updated many more times a second. The time widget looked less accurate and lagging (especially with multiple showing seconds) so the refresh interval is set to be 500 ms instead of 1 second.
This commit is contained in:
+38
-16
@@ -13,6 +13,8 @@ use eframe::egui::Ui;
|
|||||||
use eframe::egui::WidgetText;
|
use eframe::egui::WidgetText;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
use std::time::Duration;
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
/// Custom format with additive modifiers for integer format specifiers
|
/// Custom format with additive modifiers for integer format specifiers
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
@@ -83,11 +85,18 @@ pub struct DateConfig {
|
|||||||
|
|
||||||
impl From<DateConfig> for Date {
|
impl From<DateConfig> for Date {
|
||||||
fn from(value: DateConfig) -> Self {
|
fn from(value: DateConfig) -> Self {
|
||||||
|
let data_refresh_interval = 1;
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
enable: value.enable,
|
enable: value.enable,
|
||||||
format: value.format,
|
format: value.format,
|
||||||
label_prefix: value.label_prefix.unwrap_or(LabelPrefix::Icon),
|
label_prefix: value.label_prefix.unwrap_or(LabelPrefix::Icon),
|
||||||
timezone: value.timezone,
|
timezone: value.timezone,
|
||||||
|
data_refresh_interval,
|
||||||
|
last_state: String::new(),
|
||||||
|
last_updated: Instant::now()
|
||||||
|
.checked_sub(Duration::from_secs(data_refresh_interval))
|
||||||
|
.unwrap(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -138,32 +147,45 @@ pub struct Date {
|
|||||||
pub format: DateFormat,
|
pub format: DateFormat,
|
||||||
label_prefix: LabelPrefix,
|
label_prefix: LabelPrefix,
|
||||||
timezone: Option<String>,
|
timezone: Option<String>,
|
||||||
|
data_refresh_interval: u64,
|
||||||
|
last_state: String,
|
||||||
|
last_updated: Instant,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Date {
|
impl Date {
|
||||||
fn output(&mut self) -> String {
|
fn output(&mut self) -> String {
|
||||||
let formatted = match &self.timezone {
|
let mut output = self.last_state.clone();
|
||||||
Some(timezone) => match timezone.parse::<Tz>() {
|
let now = Instant::now();
|
||||||
Ok(tz) => Local::now()
|
|
||||||
.with_timezone(&tz)
|
if now.duration_since(self.last_updated) > Duration::from_secs(self.data_refresh_interval) {
|
||||||
|
let formatted = match &self.timezone {
|
||||||
|
Some(timezone) => match timezone.parse::<Tz>() {
|
||||||
|
Ok(tz) => Local::now()
|
||||||
|
.with_timezone(&tz)
|
||||||
|
.format(&self.format.fmt_string())
|
||||||
|
.to_string()
|
||||||
|
.trim()
|
||||||
|
.to_string(),
|
||||||
|
Err(_) => format!("Invalid timezone: {}", timezone),
|
||||||
|
},
|
||||||
|
None => Local::now()
|
||||||
.format(&self.format.fmt_string())
|
.format(&self.format.fmt_string())
|
||||||
.to_string()
|
.to_string()
|
||||||
.trim()
|
.trim()
|
||||||
.to_string(),
|
.to_string(),
|
||||||
Err(_) => format!("Invalid timezone: {}", timezone),
|
};
|
||||||
},
|
|
||||||
None => Local::now()
|
|
||||||
.format(&self.format.fmt_string())
|
|
||||||
.to_string()
|
|
||||||
.trim()
|
|
||||||
.to_string(),
|
|
||||||
};
|
|
||||||
|
|
||||||
// if custom modifiers are used, apply them
|
// if custom modifiers are used, apply them
|
||||||
match &self.format {
|
output = match &self.format {
|
||||||
DateFormat::CustomModifiers(custom) => custom.apply(&formatted),
|
DateFormat::CustomModifiers(custom) => custom.apply(&formatted),
|
||||||
_ => formatted,
|
_ => formatted,
|
||||||
|
};
|
||||||
|
|
||||||
|
self.last_state.clone_from(&output);
|
||||||
|
self.last_updated = now;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
output
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+85
-41
@@ -20,6 +20,8 @@ use eframe::epaint::StrokeKind;
|
|||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
use std::time::Duration;
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref TIME_RANGES: Vec<(&'static str, NaiveTime)> = {
|
static ref TIME_RANGES: Vec<(&'static str, NaiveTime)> = {
|
||||||
@@ -96,12 +98,21 @@ pub struct TimeConfig {
|
|||||||
|
|
||||||
impl From<TimeConfig> for Time {
|
impl From<TimeConfig> for Time {
|
||||||
fn from(value: TimeConfig) -> Self {
|
fn from(value: TimeConfig) -> Self {
|
||||||
|
// using 1 second made the widget look "less accurate" and lagging (especially having multiple with seconds).
|
||||||
|
// This is still better than getting an update every frame
|
||||||
|
let data_refresh_interval = 500;
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
enable: value.enable,
|
enable: value.enable,
|
||||||
format: value.format,
|
format: value.format,
|
||||||
label_prefix: value.label_prefix.unwrap_or(LabelPrefix::Icon),
|
label_prefix: value.label_prefix.unwrap_or(LabelPrefix::Icon),
|
||||||
timezone: value.timezone,
|
timezone: value.timezone,
|
||||||
changing_icon: value.changing_icon.unwrap_or_default(),
|
changing_icon: value.changing_icon.unwrap_or_default(),
|
||||||
|
data_refresh_interval_millis: data_refresh_interval,
|
||||||
|
last_state: TimeOutput::new(),
|
||||||
|
last_updated: Instant::now()
|
||||||
|
.checked_sub(Duration::from_millis(data_refresh_interval))
|
||||||
|
.unwrap(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -151,6 +162,21 @@ impl TimeFormat {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
struct TimeOutput {
|
||||||
|
label: String,
|
||||||
|
icon: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TimeOutput {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
label: String::new(),
|
||||||
|
icon: String::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Time {
|
pub struct Time {
|
||||||
pub enable: bool,
|
pub enable: bool,
|
||||||
@@ -158,14 +184,35 @@ pub struct Time {
|
|||||||
label_prefix: LabelPrefix,
|
label_prefix: LabelPrefix,
|
||||||
timezone: Option<String>,
|
timezone: Option<String>,
|
||||||
changing_icon: bool,
|
changing_icon: bool,
|
||||||
|
data_refresh_interval_millis: u64,
|
||||||
|
last_state: TimeOutput,
|
||||||
|
last_updated: Instant,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Time {
|
impl Time {
|
||||||
fn output(&mut self) -> (String, String) {
|
fn output(&mut self) -> TimeOutput {
|
||||||
let (formatted, current_time) = match &self.timezone {
|
let mut output = self.last_state.clone();
|
||||||
Some(timezone) => match timezone.parse::<Tz>() {
|
let now = Instant::now();
|
||||||
Ok(tz) => {
|
|
||||||
let dt = Local::now().with_timezone(&tz);
|
if now.duration_since(self.last_updated)
|
||||||
|
> Duration::from_millis(self.data_refresh_interval_millis)
|
||||||
|
{
|
||||||
|
let (formatted, current_time) = match &self.timezone {
|
||||||
|
Some(timezone) => match timezone.parse::<Tz>() {
|
||||||
|
Ok(tz) => {
|
||||||
|
let dt = Local::now().with_timezone(&tz);
|
||||||
|
(
|
||||||
|
dt.format(&self.format.fmt_string())
|
||||||
|
.to_string()
|
||||||
|
.trim()
|
||||||
|
.to_string(),
|
||||||
|
Some(dt.time()),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Err(_) => (format!("Invalid timezone: {:?}", timezone), None),
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
let dt = Local::now();
|
||||||
(
|
(
|
||||||
dt.format(&self.format.fmt_string())
|
dt.format(&self.format.fmt_string())
|
||||||
.to_string()
|
.to_string()
|
||||||
@@ -174,38 +221,35 @@ impl Time {
|
|||||||
Some(dt.time()),
|
Some(dt.time()),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Err(_) => (format!("Invalid timezone: {:?}", timezone), None),
|
};
|
||||||
},
|
|
||||||
None => {
|
if current_time.is_none() {
|
||||||
let dt = Local::now();
|
return TimeOutput {
|
||||||
(
|
label: formatted,
|
||||||
dt.format(&self.format.fmt_string())
|
icon: egui_phosphor::regular::WARNING_CIRCLE.to_string(),
|
||||||
.to_string()
|
};
|
||||||
.trim()
|
|
||||||
.to_string(),
|
|
||||||
Some(dt.time()),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
if current_time.is_none() {
|
let current_range = match &self.changing_icon {
|
||||||
return (
|
true => TIME_RANGES
|
||||||
formatted,
|
.iter()
|
||||||
egui_phosphor::regular::WARNING_CIRCLE.to_string(),
|
.rev()
|
||||||
);
|
.find(|&(_, start)| current_time.unwrap() > *start)
|
||||||
|
.cloned(),
|
||||||
|
false => None,
|
||||||
|
}
|
||||||
|
.unwrap_or((egui_phosphor::regular::CLOCK, NaiveTime::default()));
|
||||||
|
|
||||||
|
output = TimeOutput {
|
||||||
|
label: formatted,
|
||||||
|
icon: current_range.0.to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
self.last_state.clone_from(&output);
|
||||||
|
self.last_updated = now;
|
||||||
}
|
}
|
||||||
|
|
||||||
let current_range = match &self.changing_icon {
|
output
|
||||||
true => TIME_RANGES
|
|
||||||
.iter()
|
|
||||||
.rev()
|
|
||||||
.find(|&(_, start)| current_time.unwrap() > *start)
|
|
||||||
.cloned(),
|
|
||||||
false => None,
|
|
||||||
}
|
|
||||||
.unwrap_or((egui_phosphor::regular::CLOCK, NaiveTime::default()));
|
|
||||||
|
|
||||||
(formatted, current_range.0.to_string())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint_binary_circle(
|
fn paint_binary_circle(
|
||||||
@@ -388,13 +432,13 @@ impl BarWidget for Time {
|
|||||||
fn render(&mut self, ctx: &Context, ui: &mut Ui, config: &mut RenderConfig) {
|
fn render(&mut self, ctx: &Context, ui: &mut Ui, config: &mut RenderConfig) {
|
||||||
if self.enable {
|
if self.enable {
|
||||||
let mut output = self.output();
|
let mut output = self.output();
|
||||||
if !output.0.is_empty() {
|
if !output.label.is_empty() {
|
||||||
let use_binary_circle = output.0.starts_with('c');
|
let use_binary_circle = output.label.starts_with('c');
|
||||||
let use_binary_rectangle = output.0.starts_with('r');
|
let use_binary_rectangle = output.label.starts_with('r');
|
||||||
|
|
||||||
let mut layout_job = LayoutJob::simple(
|
let mut layout_job = LayoutJob::simple(
|
||||||
match self.label_prefix {
|
match self.label_prefix {
|
||||||
LabelPrefix::Icon | LabelPrefix::IconAndText => output.1,
|
LabelPrefix::Icon | LabelPrefix::IconAndText => output.icon,
|
||||||
LabelPrefix::None | LabelPrefix::Text => String::new(),
|
LabelPrefix::None | LabelPrefix::Text => String::new(),
|
||||||
},
|
},
|
||||||
config.icon_font_id.clone(),
|
config.icon_font_id.clone(),
|
||||||
@@ -403,12 +447,12 @@ impl BarWidget for Time {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if let LabelPrefix::Text | LabelPrefix::IconAndText = self.label_prefix {
|
if let LabelPrefix::Text | LabelPrefix::IconAndText = self.label_prefix {
|
||||||
output.0.insert_str(0, "TIME: ");
|
output.label.insert_str(0, "TIME: ");
|
||||||
}
|
}
|
||||||
|
|
||||||
if !use_binary_circle && !use_binary_rectangle {
|
if !use_binary_circle && !use_binary_rectangle {
|
||||||
layout_job.append(
|
layout_job.append(
|
||||||
&output.0,
|
&output.label,
|
||||||
10.0,
|
10.0,
|
||||||
TextFormat {
|
TextFormat {
|
||||||
font_id: config.text_font_id.clone(),
|
font_id: config.text_font_id.clone(),
|
||||||
@@ -431,9 +475,9 @@ impl BarWidget for Time {
|
|||||||
|
|
||||||
if use_binary_circle || use_binary_rectangle {
|
if use_binary_circle || use_binary_rectangle {
|
||||||
let ordered_output = if is_reversed {
|
let ordered_output = if is_reversed {
|
||||||
output.0.chars().rev().collect()
|
output.label.chars().rev().collect()
|
||||||
} else {
|
} else {
|
||||||
output.0
|
output.label
|
||||||
};
|
};
|
||||||
|
|
||||||
for (section_index, section) in
|
for (section_index, section) in
|
||||||
|
|||||||
Reference in New Issue
Block a user